Repository navigation
Description
Description
When running opencode serve, any session created and prompted through the v2 API (POST /api/session + POST /api/session/{id}/prompt) fails with a provider-side 401, because the provider key from ~/.local/share/opencode/auth.json is not attached to the outgoing LLM request. The v1 API (POST /session + POST /session/{id}/message) on the same serving instance, and the CLI (opencode run -m provider/model) in the same directory, work fine.
The v2 session/prompt calls themselves succeed (HTTP 200, prompt admitted), so callers can't see the failure through the API response. The failure is recorded on the assistant message row as finish: "error", and — importantly — no error event is emitted on the session event stream, so SDK clients just watch the turn stall forever.
Evidence
Same machine, same directory, same provider (zhipuai-coding-plan, key stored in auth.json, source: "api" in /config/providers):
| Path | Result |
|---|---|
CLI opencode run -m zhipuai-coding-plan/glm-5.2 "Reply with exactly: ok" |
✅ replies ok |
v1 SDK client.session.create() + client.session.prompt({ body: { parts: [...], model } }) → opencode serve |
✅ replies ok in ~13s |
v2 SDK client.v2.session.create({ location, agent, model }) + client.v2.session.prompt({ prompt: { text } }) → same opencode serve |
❌ 401 |
The failing turn's assistant message (fetched via GET /api/session/{id}/message):
{
"type": "assistant",
"model": {"id": "glm-5.2", "providerID": "zhipuai-coding-plan", "variant": "default"},
"finish": "error",
"error": {
"type": "unknown",
"message": "Provider request failed with HTTP 401: {\"error\":{\"code\":\"1001\",\"message\":\"Header中未收到Authorization参数,无法进行身份验证。\"}}"
}
}(The provider message translates to: "Authorization parameter not received in header, unable to authenticate.")
Notes:
/config/providerson the serving instance lists the provider withsource: "api"and the correctkeyvalue, so the config layer sees the key — it's the outgoing request that lacks theAuthorizationheader.- Reproduces for multiple
source: "api"providers (zhipuai-coding-plan, deepseek, alibaba-token-plan-cn). - Adding
variant: "default",delivery: "queue", orresume: trueto the v2 prompt makes no difference — always the same 401. - Sessions created via v2 without an explicit model also fail the same way, so it's not model-ref resolution.
Plugins
None needed to reproduce. (Machine has plugins installed globally, but the repro server is a bare opencode serve with OPENCODE_CONFIG_CONTENT only defining custom agents.)
OpenCode version
opencode 1.18.29
(@opencode-ai/sdk 1.17.13 for the SDK repro)
Steps to reproduce
mkdir -p /tmp/oc-clean-dir && cd /tmp/oc-clean-dir
opencode serve --hostname=127.0.0.1 --port=4098 &
# v2 → FAILS (assistant message gets finish:"error", provider 401)
node -e '
import("@opencode-ai/sdk/v2").then(async (m) => {
const client = m.createOpencodeClient({ baseUrl: "http://127.0.0.1:4098" });
const created = await client.v2.session.create(
{ location: { directory: "/tmp/oc-clean-dir" }, agent: "build",
model: { providerID: "zhipuai-coding-plan", id: "glm-5.2", variant: "default" } },
{ throwOnError: true });
await client.v2.session.prompt(
{ sessionID: created.data.data.id, prompt: { text: "Reply with exactly: ok" } },
{ throwOnError: true });
console.log("prompt admitted — now fetch GET /api/session/<id>/message and check finish/error");
})'
# v1 → WORKS on the same server
node -e '
import("@opencode-ai/sdk/client").then(async (m) => {
const client = m.createOpencodeClient({ baseUrl: "http://127.0.0.1:4098" });
const created = await client.session.create({ query: { directory: "/tmp/oc-clean-dir" } }, { throwOnError: true });
const res = await client.session.prompt(
{ path: { id: created.data.id },
body: { parts: [{ type: "text", text: "Reply with exactly: ok" }],
model: { providerID: "zhipuai-coding-plan", modelID: "glm-5.2" } } },
{ throwOnError: true });
console.log("v1 replied");
})'Also worth noting for the error path: even when the turn errors out this way, the session event stream (/api/session/{id}/event SSE) stays silent — only session.next.prompt.admitted and session.next.prompted events arrive. Emitting an error event (or setting an abort/error terminal state) would let SDK clients fail fast instead of polling until timeout.
Screenshot and/or share link
n/a (headless serve + SDK repro)
Operating System
Ubuntu 22.04 x86_64, Node v24.14.0
Terminal
headless (opencode serve), not TUI
Context: this breaks DevSpace's opencode subagent integration (Waishnav/devspace#302), which uses the v2 SDK exclusively.
Activity
github-actions commentedon Sep 8, 2026
This issue might be a duplicate of existing issues. Please check:
opencode servev2 session path (401) — works in run/TUI #41973: Same root cause — provider credentials not attached to LLM requests on the v2/api/sessionexecution path (in that case,{file:}apiKey references; here,auth.jsonkeys). The symptom is identical: v2 sessions 401 at the provider while v1 and CLI work fine.serve: GET /api/model omits auth.json providers— auth.json providers are invisible to the serve/v2 API layer entirely, which points to the same underlying gap (auth.json not being read by the v2 session execution path).OPENCODE_CONFIG_CONTENT/createOpencodeServer({config})are invisible to the v2 API surface, causingModelUnavailableError— same class of "v2 path doesn't see credentials that v1 and CLI do" issue.If your issue is distinct from all of the above (e.g., auth.json credentials are visible to
/config/providersbut still not forwarded in the Authorization header specifically for v2-created sessions), it may be worth noting that in a comment to help maintainers triage.fix(agents): talk to opencode over the v1 session endpoints
fix(agents): talk to opencode over the v1 session endpoints
opencodejr commentedon Oct 28, 2026
Thanks for the detailed report and the side-by-side comparison.
You're on
opencode 1.18.29with@opencode-ai/sdk1.17.13, which is OpenCode v1. v1 only gets fixes for critical bugs: data loss, security problems, or breakage with no workaround. Here the v1 API (POST /session+POST /session/{id}/message) works on the same server, so this probably won't be fixed in v1. Until then, the v1 SDK client (@opencode-ai/sdk/client) is a workaround.The
/api/sessionendpoints are developed in OpenCode v2 (npm package@opencode/cli, theopencodecommand). We'd encourage you to try v2 with the matching SDK. If you still get the missingAuthorizationheader, or no error event on the session stream when a turn fails, please reply here with the v2 version and the same repro, and we'll pick it up through the normal flow. Please also reply if you think this is critical for v1.Related, though not the same problem:
opencodejr commentedon Oct 29, 2026
Closing as not planned. This was reported on OpenCode v1 (
1.18.29), which only gets fixes for critical bugs, and the v1/sessionAPI works as a workaround. We haven't heard that it is critical or that it also happens on v2.If you try OpenCode v2 (
@opencode/cli) with the matching SDK and still see the missingAuthorizationheader on/api/sessionprompts, or no error event on the session stream when a turn fails, please open a new issue with the v2 version and your repro. Thanks again for the detailed report.