Skip to content

ClawHub requests fail when OPENCLAW_CLAWHUB_URL contains a path prefix #83975

@nicken

Description

@nicken

Bug

When OPENCLAW_CLAWHUB_URL (or CLAWHUB_URL) is set to a URL that includes a non-root path prefix (e.g. http://host:port/prefix), all ClawHub API calls return 404.

Root Cause

src/infra/clawhub.tsbuildUrl() (line 553):

const url = new URL(params.path, `${normalizeBaseUrl(params.baseUrl)}/`);

new URL() treats a leading-/ path as absolute and replaces the base URL's entire pathname:

new URL("/api/v1/search", "http://host:port/prefix/")
→ "http://host:port/api/v1/search"   // /prefix dropped

Expected: http://host:port/prefix/api/v1/search

This affects every endpoint (/api/v1/search, /api/v1/skills/*, /api/v1/packages/*, /api/v1/download, etc.).

Reproduction

# With a reverse-proxied ClawHub instance behind a path prefix:
export OPENCLAW_CLAWHUB_URL=http://clawhub.internal:8080/clawhub

# Works (clawhub CLI):
clawhub search "foo"     # → results

# Broken (openclaw):
openclaw skills search "foo"   # → ClawHubRequestError: 404 Not Found

Direct curl to the full path confirms the endpoint is alive:

curl "http://clawhub.internal:8080/clawhub/api/v1/search?q=foo"  # 200 OK
curl "http://clawhub.internal:8080/api/v1/search?q=foo"           # 404 (what openclaw actually hits)

Suggested Fix

Replace new URL(path, base) with string concatenation to preserve the base path:

function buildUrl(params: Pick<ClawHubRequestParams, "baseUrl" | "path" | "search">): URL {
  const base = normalizeBaseUrl(params.baseUrl);
  const url = new URL(`${base}${params.path}`);
  for (const [key, value] of Object.entries(params.search ?? {})) {
    if (!value) continue;
    url.searchParams.set(key, value);
  }
  return url;
}

Or alternatively, ensure normalizeBaseUrl strips trailing slashes and params.path is joined without the leading /.

Environment

  • openclaw version: current main (commit 041266a)
  • Deployment: Docker container, ClawHub behind nginx reverse proxy with URL prefix

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions