Skip to content

opencode serve: provider auth (auth.json key) not attached to LLM requests for sessions created via the v2 API (/api/session) — works on v1 (/session) #47888

Closed as not planned

Description

@yulong-ge

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/providers on the serving instance lists the provider with source: "api" and the correct key value, so the config layer sees the key — it's the outgoing request that lacks the Authorization header.
  • Reproduces for multiple source: "api" providers (zhipuai-coding-plan, deepseek, alibaba-token-plan-cn).
  • Adding variant: "default", delivery: "queue", or resume: true to 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

  1. github-actions commented on Sep 8, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If your issue is distinct from all of the above (e.g., auth.json credentials are visible to /config/providers but 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.

  2. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed report and the side-by-side comparison.

    You're on opencode 1.18.29 with @opencode-ai/sdk 1.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/session endpoints are developed in OpenCode v2 (npm package @opencode/cli, the opencode command). We'd encourage you to try v2 with the matching SDK. If you still get the missing Authorization header, 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:

  3. opencodejr commented on Oct 29, 2026

    @opencodejr
    Contributor

    Closing as not planned. This was reported on OpenCode v1 (1.18.29), which only gets fixes for critical bugs, and the v1 /session API 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 missing Authorization header on /api/session prompts, 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions