You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
opencode api and session import drop the --server path prefix #60542
With a --server URL that has a path prefix, opencode api and opencode session import connect, then send their request without the prefix.
#50428 fixed the connection check, which goes through the generated client, so --server http://host/prefix now connects. But both commands then build the request by hand with new URL("/api/...", serverUrl), and the leading slash drops the prefix.
This was reported in #46498, which was closed as a duplicate of #50427 before the reporter replied. I have a fix with tests and will open a PR.
Plugins
No response
OpenCode version
v2.2.2
Steps to reproduce
opencode serve --port 4096
Reverse proxy mounting it under /proxy/, e.g. nginx location /proxy/ { proxy_pass http://127.0.0.1:4096/; }
opencode api --server http://127.0.0.1:8080/proxy GET /api/session
The request goes to /api/session instead of /proxy/api/session and gets a 404
Thanks for the clear report. I could reproduce this on v2.2.2, and it still happens on the latest dev (92b2ca0).
Setup: opencode serve --port 4096 (with OPENCODE_PASSWORD) behind a small proxy that serves it under /proxy/, strips the prefix and logs each path it receives. Each command ran with --server http://127.0.0.1:8080/proxy:
The connection check and /api/location go through the generated client and keep the prefix (/proxy/api/info, /proxy/api/location).
opencode api ... GET /api/session sends GET /api/session and gets HTTP 404 Not Found.
opencode api ... session.list (an operation name) sends GET /openapi.json and fails with Failed to load OpenAPI document: HTTP 404. Your report doesn't mention this case, but it's the same problem.
opencode session import ... sends POST /api/experimental/session/import and fails with Failed to import session: Not Found.
This matches your analysis: the new URL("/...", serverUrl) calls in packages/cli/src/commands/handlers/api.ts and session/import.ts drop the base path. The /openapi.json fetch in api.ts needs the same fix as the other two. The script below reproduces it.
Related: #50427 / #50428 (the same fix for the generated client), #46498 (the earlier report of this problem), #47442 (an earlier PR that also covered these commands).
Reproduction script (repro.sh)
#!/usr/bin/env bash# Reproduces: `opencode api` / `opencode session import` drop the --server path prefix.# Usage: ./repro.sh (uses `opencode` from PATH)# OC_DEV=/path/to/repo ./repro.sh (runs CLI from source checkout)set -u
WORK=$(mktemp -d /tmp/opencode/prefix-XXXX)cd"$WORK"export OPENCODE_PASSWORD=repro-secret
export XDG_DATA_HOME="$WORK/data" XDG_CONFIG_HOME="$WORK/config" XDG_STATE_HOME="$WORK/state" XDG_CACHE_HOME="$WORK/cache"oc() {
if [ -n"${OC_DEV:-}" ];then
bun --conditions=browser --preload="$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js""$OC_DEV/packages/cli/src/index.ts""$@"else
opencode "$@"fi
}
echo"version: $(oc --version)"
oc serve --port 4096 >"$WORK/serve.log"2>&1&
SERVE=$!# Reverse proxy mounting the server under /proxy/ (strips the prefix), like nginx# `location /proxy/ { proxy_pass http://127.0.0.1:4096/; }`. Anything else -> 404.
cat >"$WORK/proxy.ts"<<'EOF'Bun.serve({ port: 8080, async fetch(req) { const url = new URL(req.url) console.log(`proxy: ${req.method} ${url.pathname}`) if (!url.pathname.startsWith("/proxy/")) return new Response("not found (no /proxy prefix)", { status: 404 }) const target = "http://127.0.0.1:4096" + url.pathname.slice("/proxy".length) + url.search return fetch(target, { method: req.method, headers: req.headers, body: req.body, redirect: "manual" }) },})EOF
bun "$WORK/proxy.ts">"$WORK/proxy.log"2>&1&
PROXY=$!trap'kill $SERVE $PROXY 2>/dev/null; pkill -f "serve --port 4096" 2>/dev/null' EXIT
foriin$(seq 1 60);do curl -sf -u opencode:repro-secret http://127.0.0.1:8080/proxy/api/info >/dev/null &&break; sleep 1;doneecho"--- curl through proxy (works):"
curl -s -u opencode:repro-secret -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:8080/proxy/api/session
echo"--- opencode api --server http://127.0.0.1:8080/proxy GET /api/session"
oc api --server http://127.0.0.1:8080/proxy GET /api/session;echo"exit $?"echo"--- opencode api --server http://127.0.0.1:8080/proxy session.list (operation id -> /openapi.json)"
oc api --server http://127.0.0.1:8080/proxy session.list;echo"exit $?"echo'{"info":{},"messages":[]}'>"$WORK/session.json"echo"--- opencode session import --server http://127.0.0.1:8080/proxy session.json"
oc session import --server http://127.0.0.1:8080/proxy "$WORK/session.json";echo"exit $?"echo"--- paths the proxy received:"
cat "$WORK/proxy.log"
Activity
opencodejr commentedon Oct 30, 2026
Thanks for the clear report. I could reproduce this on v2.2.2, and it still happens on the latest
dev(92b2ca0).Setup:
opencode serve --port 4096(withOPENCODE_PASSWORD) behind a small proxy that serves it under/proxy/, strips the prefix and logs each path it receives. Each command ran with--server http://127.0.0.1:8080/proxy:/api/locationgo through the generated client and keep the prefix (/proxy/api/info,/proxy/api/location).opencode api ... GET /api/sessionsendsGET /api/sessionand getsHTTP 404 Not Found.opencode api ... session.list(an operation name) sendsGET /openapi.jsonand fails withFailed to load OpenAPI document: HTTP 404. Your report doesn't mention this case, but it's the same problem.opencode session import ...sendsPOST /api/experimental/session/importand fails withFailed to import session: Not Found.This matches your analysis: the
new URL("/...", serverUrl)calls inpackages/cli/src/commands/handlers/api.tsandsession/import.tsdrop the base path. The/openapi.jsonfetch inapi.tsneeds the same fix as the other two. The script below reproduces it.Related: #50427 / #50428 (the same fix for the generated client), #46498 (the earlier report of this problem), #47442 (an earlier PR that also covered these commands).
Reproduction script (repro.sh)
Run it:
bash repro.sh