openclaw - ✅(Solved) Fix ClawHub requests fail when OPENCLAW_CLAWHUB_URL contains a path prefix [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#83975Fetched 2026-05-20 03:45:40
View on GitHub
Comments
1
Participants
2
Timeline
10
Reactions
1
Author
Timeline (top)
labeled ×5cross-referenced ×2closed ×1commented ×1

Error Message

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

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.).

Fix Action

Fixed

PR fix notes

PR #83982: fix(clawhub): preserve base URL path prefix [AI-assisted]

Description (problem / solution / changelog)

Summary

  • Problem: ClawHub requests dropped non-root path prefixes from OPENCLAW_CLAWHUB_URL / CLAWHUB_URL, causing reverse-proxied ClawHub deployments to hit /api/... instead of /prefix/api/....
  • Solution: Build ClawHub request URLs from the normalized base URL first, then append the request path onto the existing base pathname.
  • What changed: Updated src/infra/clawhub.ts URL construction and added a focused regression test in src/infra/clawhub.test.ts.
  • What did NOT change (scope boundary): No endpoint schemas, auth/token handling, downloads, install logic, or default ClawHub URL behavior changed.

AI-assisted: yes.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #83975
  • This PR fixes a bug or regression

Motivation

  • Reverse-proxied ClawHub deployments under a path prefix cannot be used from OpenClaw because every API request silently drops that prefix and returns 404.

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: ClawHub API requests preserve a configured base URL path prefix.
  • Real environment tested: Local OpenClaw checkout on Linux with Node v22.21.1 and a local HTTP server standing in for a reverse-proxied ClawHub endpoint under /clawhub.
  • Exact steps or command run after this patch:
    • OPENCLAW_CLAWHUB_URL=http://127.0.0.1:18799/clawhub node --import tsx -e 'const { searchClawHubSkills } = await import("./src/infra/clawhub.ts"); const results = await searchClawHubSkills({ query: "calendar" }); console.log(JSON.stringify(results));'
  • Evidence after fix (copied live terminal output from the real OpenClaw checkout):
SERVER GET /clawhub/api/v1/search?q=calendar
[{"slug":"calendar","displayName":"Calendar","version":"1.0.0","summary":"demo"}]
  • Observed result after fix: The request hit /clawhub/api/v1/search, and the search result was returned successfully.
  • What was not tested: A live external ClawHub deployment behind nginx; full repository test suite.
  • Before evidence: Issue #83975 documents the pre-fix behavior where new URL("/api/v1/search", "http://host:port/prefix/") drops /prefix.

Root Cause (if applicable)

  • Root cause: new URL(params.path, base) treats leading-slash request paths as absolute paths and replaces the base URL pathname.
  • Missing detection / guardrail: Existing ClawHub tests covered root-hosted base URLs but not base URLs with non-root path prefixes.
  • Contributing context (if known): The ClawHub request paths are intentionally absolute-looking (/api/v1/...), which is correct for root-hosted deployments but unsafe when passed directly to URL resolution with a prefixed base.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/infra/clawhub.test.ts
  • Scenario the test should lock in: OPENCLAW_CLAWHUB_URL=https://internal.example.com/clawhub plus searchClawHubSkills({ query: "calendar" }) requests /clawhub/api/v1/search?q=calendar.
  • Why this is the smallest reliable guardrail: The bug is entirely in ClawHub URL construction, so the helper-level test catches it without requiring network or install flows.
  • Existing test that already covers this (if any): None.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

OpenClaw now supports ClawHub base URLs configured with a non-root path prefix, for example OPENCLAW_CLAWHUB_URL=http://host:port/clawhub.

Diagram (if applicable)

Before:
OPENCLAW_CLAWHUB_URL=http://host/clawhub -> /api/v1/search -> 404

After:
OPENCLAW_CLAWHUB_URL=http://host/clawhub -> /clawhub/api/v1/search -> 200

Security Impact (required)

  • New permissions/capabilities? (Yes/No): No
  • Secrets/tokens handling changed? (Yes/No): No
  • New/changed network calls? (Yes/No): No
  • Command/tool execution surface changed? (Yes/No): No
  • Data access scope changed? (Yes/No): No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux
  • Runtime/container: Node v22.21.1, local checkout
  • Model/provider: N/A
  • Integration/channel (if any): ClawHub HTTP API helper
  • Relevant config (redacted): OPENCLAW_CLAWHUB_URL=http://127.0.0.1:18799/clawhub

Steps

  1. Start a local HTTP server that returns 200 only for /clawhub/api/v1/search.
  2. Set OPENCLAW_CLAWHUB_URL to the local server URL with /clawhub path prefix.
  3. Run searchClawHubSkills({ query: "calendar" }) through node --import tsx.

Expected

  • The request preserves /clawhub and returns search results.

Actual

  • The request preserved /clawhub and returned search results.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Focused validation run:

OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs run --config test/vitest/vitest.infra.config.ts src/infra/clawhub.test.ts

Test Files  1 passed (1)
Tests  39 passed | 2 skipped (41)

Live local HTTP proof after patch:

SERVER GET /clawhub/api/v1/search?q=calendar
[{"slug":"calendar","displayName":"Calendar","version":"1.0.0","summary":"demo"}]

Human Verification (required)

  • Verified scenarios: Focused ClawHub infra tests; local HTTP path-prefix request proof.
  • Edge cases checked: Existing ClawHub tests still pass for root-hosted default paths.
  • What you did not verify: Full test suite, live external ClawHub behind nginx.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No): Yes
  • Config/env changes? (Yes/No): No
  • Migration needed? (Yes/No): No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: URL path joining could affect existing root-hosted ClawHub requests.
    • Mitigation: Existing ClawHub helper tests still pass, and the new path-prefix test covers the previously missing case.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/infra/clawhub.test.ts (modified, +24/-0)
  • src/infra/clawhub.ts (modified, +4/-1)

PR #84148: fix(clawhub): preserve URL path prefix in buildUrl

Description (problem / solution / changelog)

Summary

When OPENCLAW_CLAWHUB_URL contains a path prefix (e.g. http://host:8080/prefix), all ClawHub API calls return 404 because new URL(path, base) treats a leading-slash path as absolute, silently dropping the base URL's pathname.

Root Cause

src/infra/clawhub.ts:554 — the two-argument new URL("/api/v1/search", "http://host:8080/prefix/") replaces the entire pathname of the base URL with the absolute path, discarding /prefix.

Fix

Switch to single-argument URL construction: new URL(\${normalizeBaseUrl(base)}${path}`). This works because normalizeBaseUrlalready strips trailing slashes and all 14 call sites use/api/v1/...` literals with leading slashes.

Tests

3 new tests covering path-prefix preservation, no-prefix compatibility, and search params with prefix. All 43 existing clawhub tests pass.

Fixes #83975

Changed files

  • src/infra/clawhub.test.ts (modified, +32/-0)
  • src/infra/clawhub.ts (modified, +2/-2)

Code Example

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

---

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

---

# 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

---

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)

---

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;
}
RAW_BUFFERClick to expand / collapse

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

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix ClawHub requests fail when OPENCLAW_CLAWHUB_URL contains a path prefix [2 pull requests, 1 comments, 2 participants]