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 Go requests are missing x-opencode-session #3344
OpenCode Go inference requests (/v1/chat/completions)
Current behaviour
On 3 September 2026, I received an email from updates@opencode.ai, subject “Missing OpenCode Go Header.” It says some requests are missing x-opencode-session, identifies their user agent as Bun fetch, and warns that requests without the header may error starting 09/06.
OpenCodex uses Bun for upstream requests and does not appear to send this header.
Expected behaviour
OpenCodex should send x-opencode-session: <stable-id-per-conversation> with OpenCode Go requests.
Minimal redacted request or reproduction
1. Configure OpenCode Go in OpenCodex.
2. Use an opencode-go model from Codex App.
3. Send multiple turns in one task.
4. The provider reports that requests from "Bun fetch" lack x-opencode-session.
Actual response or error
Provider email: requests without x-opencode-session may error starting 09/06.
User agent: Bun fetch
Upstream documentation
No public specification found. This requirement was communicated directly by updates@opencode.ai on 3 September 2026.
Suggested mapping or implementation notes
Send a stable opaque value per conversation, as requested by the provider.
이 이슈는 OpenCode Go(opencode-go)로 나가는 요청에 x-opencode-session 헤더가 없어서, 업스트림이 09/06부터 그 요청을 거절할 수 있다는 경고다. 보고자(colthreepv)는 2026-09-03에 updates@opencode.ai에서 "Missing OpenCode Go Header" 메일을 받았고, User-Agent가 Bun fetch로 찍혔다고 한다. OpenCodex는 업스트림 fetch에 Bun을 쓰므로, 메일 대상이 이 프로젝트(또는 같은 런타임을 쓰는 다른 프록시)일 가능성이 높다.
지금 dev HEAD는 b15cbb2c3 (package 2.41.0)이다. src/providers/registry.ts의 opencode-go 줄(대략 1572행부터)을 보면 baseUrl은 https://opencode.ai/zen/go/v1, adapter는 openai-chat(일부 모델만 modelWireDefaults로 openai-responses)이고, staticHeaders가 없다. 반대로 같은 파일의 opencode-free는 #2160에서 이미 User-Agent: opencode와 x-opencode-client: desktop를 staticHeaders에 넣었다. 헤더는 mergeRegistryStaticHeaders(registry.ts)가 router.ts resolve 시점에 합치고, openai-chat.ts / openai-responses.ts가 provider.headers로 업스트림에 실어 보낸다. 저장소 전체를 찾아도 x-opencode-session 문자열은 코드에 없고, devlog/_plan/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md에만 "당시 429 수정에는 불필요 / 대화 파생 세션 ID는 프라이버시 이슈라 별도 증거가 필요"라고 적어 두고 일부러 안 넣었던 흔적만 있다. 그 판단은 그 시점의 opencode-free 429에는 맞았지만, 지금은 업스트림이 Go에 대해 헤더를 요구한다고 직접 통보한 상태라 전제가 바뀌었다.
왜 중요한가. opencode-go는 featured 키 프로바이더이고 Codex App에서 많이 쓴다. 09/06이 지나면 "가끔 429"가 아니라 요청 자체가 깨질 수 있다. 오늘은 09/03(KST)이라 남은 시간이 짧다. staticHeaders에 고정 문자열만 넣는 방식은 opencode-free의 User-Agent 수정과는 성격이 다르다. 메일이 요구하는 값은 대화마다 안정적인 opaque id이기 때문이다. 고정 UUID 하나를 전 요청에 붙이면 "헤더는 있다"만 만족하고, 세션 단위 추적은 사실상 무력화된다. 대화마다 다른 값을 넣으려면 registry 정적 헤더만으로는 부족하고, 요청 경로에서 conversation/thread 정체성을 읽어 헤더를 채우는 동적 처리가 필요하다. 이미 비슷한 패턴이 있다. src/providers/xai-transport.ts의 x-grok-conv-id / x-grok-session-id affinity, src/adapters/kiro-wire.ts의 stableConversationId가 그 예다. OmniRoute(open-sse/executors/opencode.ts)도 예전에 conversation 파생 또는 UUID로 x-opencode-session을 보낸다고 우리 plan 문서에 기록돼 있다.
공개 스펙 URL은 아직 없다(이슈에도 "No public specification found"). 그래서 구현 전에 확인할 것은 (1) 값이 정말 per-conversation opaque여야 하는지, (2) Chat(/v1/chat/completions)만이 아니라 Responses 경로(gpt-5.6-luna, muse-spark-*의 modelWireDefaults)에도 같은 헤더가 필요한지, (3) opencode-zen / opencode-free에도 같은 규칙이 곧 적용되는지다. 그래도 "메일 + Bun fetch + 09/06"이면 우선순위는 높다. types.ts/config.ts 분할 캠페인과는 무관한 프로바이더 호환 핫픽스라서, 그 분할에 묶지 말고 독립 PR로 빠르게 넣는 편이 맞다.
라인 - 문제
src/providers/registry.tsopencode-go 엔트리 - staticHeaders가 없어 User-Agent/x-opencode-session을 registry 기본값으로 실어 보내지 않는다. 업스트림에는 Bun 기본 UA만 보일 수 있다. x-opencode-session (저장소 전체) - 심볼/문자열이 코드에 없다. 09/06 강제 전에 헤더를 붙이는 경로가 아직 없다. src/adapters/openai-chat.tsopenAIChatTransport - provider.headers만 합친다. 대화별 세션 ID를 여기서(또는 상위 resolve에서) 채우는 로직이 없다. src/adapters/openai-responses.ts outbound headers - Go의 Luna/Muse Spark Responses 경로에도 동일 헤더가 필요할 수 있는데, 지금 코드는 대화 세션 헤더를 넣지 않는다. devlog/.../080_residual_dispositions.md - #2160 때 x-opencode-session을 의도적으로 제외했다. 그 전제(증거 없음)는 이번 업스트림 메일로 깨졌으니, Go 쪽은 재검토가 필요하다.
관련 #2160 - opencode-free의 UA/x-opencode-client만 다뤘고 Go 세션 헤더는 범위 밖이었다. 이 이슈의 직접 수정이 아니다.
적용 범위: opencode-go만 먼저 할지, opencode-zen/opencode-free까지 같은 헤더를 미리 넣을지.
고정 헤더 vs 동적 헤더: 임시로 프로세스/설치 단위 고정값을 넣어 09/06 거절만 막을지, 처음부터 per-conversation으로 갈지.
메일 원문/스펙: 가능하면 updates@opencode.ai 요구사항(필수 여부, 값 형식, Chat vs Responses)을 이슈에 붙여 재현 기준을 고정할지.
너의 추천
help wanted보다 우선 핫픽스로 본다. opencode-go 요청(Chat + 해당 Responses 모델)에 per-conversation(또는 최소한 per-task) opaque x-opencode-session을 붙이는 작은 PR을 09/06 전에 dev에 랜딩하자. 구현은 xai-transport affinity / kiro-wirestableConversationId 패턴을 참고하고, registry staticHeaders만으로는 부족하니 요청 경로에서 동적으로 넣자. 공개 스펙이 없어도 메일 데드라인은 실재하니, 값 형식은 opaque UUID로 시작하고 업스트림 확인이 오면 조정하면 된다. 중복 이슈는 없고 types 분할에도 묶지 말 것.
2.40.0 — tag and main both resolved to commit 35ff3a462e786bd5efc394dfb1a8a5cc946e454f on 2026-09-03.
Runtime / OS
Windows x64
Bun 1.3.14
Summary
OpenCodex 2.40.0 does not send x-opencode-session on OpenCode Go inference requests.
On 2026-09-03, OpenCode emailed that requests identified as “Bun fetch” were missing this header and may start failing on 2026-09-06. The deadline comes from that direct provider notification; I could not find a public specification for the enforcement date.
The missing header is independently confirmed by:
static inspection of the exact 2.40.0 source; and
a non-billable loopback wire probe using the installed OpenCodex adapter and Bun fetch.
The official OpenCode client sends its stable session ID as x-opencode-session for OpenCode providers, and the current Zen handler uses the value as its sticky-routing key.
Current behavior
The opencode-go registry entry defines the canonical Go endpoint and its wire defaults, but no session header:
Provider transport enrichment runs before final wire selection, but currently handles GitHub Copilot and xAI only. All other providers are returned unchanged:
A repository/source search under src/ finds no x-opencode-session implementation.
Minimal non-billable reproduction
I imported buildOpenAIChatPassthroughRequest from the installed 2.40.0 package, replaced only the provider base URL with a Bun loopback server, built an ordinary Chat request, and dispatched it with Bun's native fetch.
The capture was sanitized to booleans and non-secret values:
No request reached opencode.ai; no real key, prompt, or billable model was used.
Expected behavior
Every OpenCode Go inference request that has a stable conversation identity should include exactly one:
x-opencode-session: <stable opaque id for this conversation lane>
The value should:
remain stable across turns and retries in the same conversation;
differ across unrelated conversations;
differ across sibling subagents under the same parent task;
not expose a raw Codex thread/session identifier;
not be persisted into the user's provider configuration;
not leak to non-OpenCode Go destinations.
Upstream evidence
The official OpenCode client sends input.sessionID in x-opencode-session, together with its request/project/client metadata, for providers whose IDs start with opencode:
The current Zen handler reads the header, uses it as stickyId, looks up the sticky provider before provider selection, includes it in metrics, and stores a truncated value in usage records:
So this is routing/correlation metadata, not only an optional analytics tag.
Suggested implementation boundary
The safest location appears to be the existing runtime transport-enrichment stage, before resolveWireProtocolOverride, rather than duplicating logic in each adapter.
Suggested behavior:
Compute the existing sessionLaneIdFromRequest(req.headers) once. It already combines parent + specific child identity and explicitly avoids collapsing sibling subagents:
Pass that lane into provider transport resolution.
Identify the canonical OpenCode Go destination before the wire override, including aliases such as opencode-go-2. registryEntryForProviderDestination is already used by the quota path for this exact alias/destination problem.
Derive an opaque, domain-separated SHA-256 value from the lane (for example, ocx_ plus 32 hex characters). This mirrors the existing deriveXaiConvId privacy pattern without sending the raw internal ID.
Add the derived value to runtime-only provider.headers, allowing the existing Chat/Responses adapters and explicit wire overrides to carry it.
Preserve an explicitly configured operator header case-insensitively, following the precedent established in PR #2160. A fixed manual value should be documented as sharing affinity across conversations.
If no stable identity exists, do not generate a fresh UUID per request. That would satisfy header presence while defeating session affinity. A promptCacheKey fallback should only be used when it is known not to represent a shared cohort.
This should not be implemented as a registry staticHeaders value: a global static session ID would merge every conversation into one upstream affinity group. An analogous client bug documents that failure mode: earendil-works/pi #4847.
Acceptance criteria / tests
RED-first unit test: same lane produces the same opaque ID.
Different conversations produce different IDs.
Same parent + different child thread/session produces different IDs.
The generated value contains no raw thread/session identifier.
Canonical OpenCode Go and a valid alias receive the header.
A noncanonical/lookalike endpoint and unrelated providers do not receive it.
A case-variant explicit operator header wins without duplication.
Chat and Responses wire requests carry the same conversation value; cover Anthropic too if a supported override can select it.
Same-target retries, 429/5xx replay, and key rotation preserve the conversation value.
Exported/persisted config does not contain the derived value.
Focused provider/router tests, typecheck, full relevant suite, and privacy scan pass.
Risks / additional context
OpenCode issue #46011 reports a recent, model-specific kimi-k2.7-code shard problem where a particular session ID consistently selects a failing replica. This is an upstream sticky-routing defect, not a reason to send a random value or omit a now-required header. A new conversation provides a different affinity key as a temporary workaround.
The generated ID is intentionally correlatable within one conversation because that is the header's purpose. Hashing/domain separation limits disclosure of OpenCodex's internal identifiers.
No live/billable OpenCode Go request was made for this report.
Closing in favor of #3378, which tracks both OpenCode Go wire-contract defects together.
Thank you @colthreepv — your report on the missing x-opencode-session header was accurate and reproducible.
Verified. Confirmed: the opencode-go registry row in src/providers/registry.ts defines no session-header behavior, and x-opencode-session does not appear anywhere under src/.
This is grouped with the other open opencode-go defect because both have the same cause — a provider-specific wire requirement the adapter does not represent — and fixing them in one pass avoids a second round of the same investigation. #3378 names this issue and credits you.
Activity
github-actions commentedon Sep 3, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
lidge-jun commentedon Sep 3, 2026
리뷰 · 우선순위 74 / 80
설명
이 이슈는 OpenCode Go(
opencode-go)로 나가는 요청에x-opencode-session헤더가 없어서, 업스트림이 09/06부터 그 요청을 거절할 수 있다는 경고다. 보고자(colthreepv)는 2026-09-03에updates@opencode.ai에서 "Missing OpenCode Go Header" 메일을 받았고, User-Agent가 Bun fetch로 찍혔다고 한다. OpenCodex는 업스트림 fetch에 Bun을 쓰므로, 메일 대상이 이 프로젝트(또는 같은 런타임을 쓰는 다른 프록시)일 가능성이 높다.지금
devHEAD는b15cbb2c3(package 2.41.0)이다.src/providers/registry.ts의opencode-go줄(대략 1572행부터)을 보면baseUrl은https://opencode.ai/zen/go/v1, adapter는openai-chat(일부 모델만modelWireDefaults로openai-responses)이고,staticHeaders가 없다. 반대로 같은 파일의opencode-free는#2160에서 이미User-Agent: opencode와x-opencode-client: desktop를staticHeaders에 넣었다. 헤더는mergeRegistryStaticHeaders(registry.ts)가router.tsresolve 시점에 합치고,openai-chat.ts/openai-responses.ts가provider.headers로 업스트림에 실어 보낸다. 저장소 전체를 찾아도x-opencode-session문자열은 코드에 없고,devlog/_plan/260820_bug_pr_backlog_consolidation/080_residual_dispositions.md에만 "당시 429 수정에는 불필요 / 대화 파생 세션 ID는 프라이버시 이슈라 별도 증거가 필요"라고 적어 두고 일부러 안 넣었던 흔적만 있다. 그 판단은 그 시점의opencode-free429에는 맞았지만, 지금은 업스트림이 Go에 대해 헤더를 요구한다고 직접 통보한 상태라 전제가 바뀌었다.왜 중요한가.
opencode-go는 featured 키 프로바이더이고 Codex App에서 많이 쓴다. 09/06이 지나면 "가끔 429"가 아니라 요청 자체가 깨질 수 있다. 오늘은 09/03(KST)이라 남은 시간이 짧다.staticHeaders에 고정 문자열만 넣는 방식은opencode-free의 User-Agent 수정과는 성격이 다르다. 메일이 요구하는 값은 대화마다 안정적인 opaque id이기 때문이다. 고정 UUID 하나를 전 요청에 붙이면 "헤더는 있다"만 만족하고, 세션 단위 추적은 사실상 무력화된다. 대화마다 다른 값을 넣으려면 registry 정적 헤더만으로는 부족하고, 요청 경로에서 conversation/thread 정체성을 읽어 헤더를 채우는 동적 처리가 필요하다. 이미 비슷한 패턴이 있다.src/providers/xai-transport.ts의x-grok-conv-id/x-grok-session-idaffinity,src/adapters/kiro-wire.ts의stableConversationId가 그 예다. OmniRoute(open-sse/executors/opencode.ts)도 예전에 conversation 파생 또는 UUID로x-opencode-session을 보낸다고 우리 plan 문서에 기록돼 있다.공개 스펙 URL은 아직 없다(이슈에도 "No public specification found"). 그래서 구현 전에 확인할 것은 (1) 값이 정말 per-conversation opaque여야 하는지, (2) Chat(
/v1/chat/completions)만이 아니라 Responses 경로(gpt-5.6-luna,muse-spark-*의modelWireDefaults)에도 같은 헤더가 필요한지, (3)opencode-zen/opencode-free에도 같은 규칙이 곧 적용되는지다. 그래도 "메일 + Bun fetch + 09/06"이면 우선순위는 높다. types.ts/config.ts 분할 캠페인과는 무관한 프로바이더 호환 핫픽스라서, 그 분할에 묶지 말고 독립 PR로 빠르게 넣는 편이 맞다.라인 - 문제
src/providers/registry.tsopencode-go엔트리 -staticHeaders가 없어 User-Agent/x-opencode-session을 registry 기본값으로 실어 보내지 않는다. 업스트림에는 Bun 기본 UA만 보일 수 있다.x-opencode-session(저장소 전체) - 심볼/문자열이 코드에 없다. 09/06 강제 전에 헤더를 붙이는 경로가 아직 없다.src/adapters/openai-chat.tsopenAIChatTransport-provider.headers만 합친다. 대화별 세션 ID를 여기서(또는 상위 resolve에서) 채우는 로직이 없다.src/adapters/openai-responses.tsoutbound headers - Go의 Luna/Muse Spark Responses 경로에도 동일 헤더가 필요할 수 있는데, 지금 코드는 대화 세션 헤더를 넣지 않는다.devlog/.../080_residual_dispositions.md-#2160때x-opencode-session을 의도적으로 제외했다. 그 전제(증거 없음)는 이번 업스트림 메일로 깨졌으니, Go 쪽은 재검토가 필요하다.관련
#2160-opencode-free의 UA/x-opencode-client만 다뤘고 Go 세션 헤더는 범위 밖이었다. 이 이슈의 직접 수정이 아니다.메인테이너의 판단이 필요한 지점
_providerContinuation에 넣을지.opencode-go만 먼저 할지,opencode-zen/opencode-free까지 같은 헤더를 미리 넣을지.updates@opencode.ai요구사항(필수 여부, 값 형식, Chat vs Responses)을 이슈에 붙여 재현 기준을 고정할지.너의 추천
help wanted보다 우선 핫픽스로 본다.opencode-go요청(Chat + 해당 Responses 모델)에 per-conversation(또는 최소한 per-task) opaquex-opencode-session을 붙이는 작은 PR을 09/06 전에dev에 랜딩하자. 구현은xai-transportaffinity /kiro-wirestableConversationId패턴을 참고하고, registrystaticHeaders만으로는 부족하니 요청 경로에서 동적으로 넣자. 공개 스펙이 없어도 메일 데드라인은 실재하니, 값 형식은 opaque UUID로 시작하고 업스트림 확인이 오면 조정하면 된다. 중복 이슈는 없고 types 분할에도 묶지 말 것.이 댓글은 grok-bot이 작성했습니다
matheussilva421 commentedon Sep 3, 2026
Client or integration
Codex App through OpenCodex
Provider or upstream service
OpenCode Go (
opencode-go)OpenCodex version
2.40.0 — tag and
mainboth resolved to commit35ff3a462e786bd5efc394dfb1a8a5cc946e454fon 2026-09-03.Runtime / OS
Summary
OpenCodex 2.40.0 does not send
x-opencode-sessionon OpenCode Go inference requests.On 2026-09-03, OpenCode emailed that requests identified as “Bun fetch” were missing this header and may start failing on 2026-09-06. The deadline comes from that direct provider notification; I could not find a public specification for the enforcement date.
The missing header is independently confirmed by:
The official OpenCode client sends its stable session ID as
x-opencode-sessionfor OpenCode providers, and the current Zen handler uses the value as its sticky-routing key.Current behavior
The
opencode-goregistry entry defines the canonical Go endpoint and its wire defaults, but no session header:src/providers/registry.ts:1475-1490The Chat adapter materializes
Content-Type, authorization, router defaults, andprovider.headers; it does not derive a session header:src/adapters/openai-chat.ts:84-99Provider transport enrichment runs before final wire selection, but currently handles GitHub Copilot and xAI only. All other providers are returned unchanged:
src/server/responses/core.ts:3427-3435src/providers/xai-transport.ts:113-168A repository/source search under
src/finds nox-opencode-sessionimplementation.Minimal non-billable reproduction
I imported
buildOpenAIChatPassthroughRequestfrom the installed 2.40.0 package, replaced only the provider base URL with a Bun loopback server, built an ordinary Chat request, and dispatched it with Bun's nativefetch.The capture was sanitized to booleans and non-secret values:
{ "userAgent": "Bun/1.3.14", "hasOpenCodeSession": false, "hasAuthorization": true, "contentType": "application/json" }No request reached
opencode.ai; no real key, prompt, or billable model was used.Expected behavior
Every OpenCode Go inference request that has a stable conversation identity should include exactly one:
x-opencode-session: <stable opaque id for this conversation lane>The value should:
Upstream evidence
The official OpenCode client sends
input.sessionIDinx-opencode-session, together with its request/project/client metadata, for providers whose IDs start withopencode:The current Zen handler reads the header, uses it as
stickyId, looks up the sticky provider before provider selection, includes it in metrics, and stores a truncated value in usage records:So this is routing/correlation metadata, not only an optional analytics tag.
Suggested implementation boundary
The safest location appears to be the existing runtime transport-enrichment stage, before
resolveWireProtocolOverride, rather than duplicating logic in each adapter.Suggested behavior:
sessionLaneIdFromRequest(req.headers)once. It already combines parent + specific child identity and explicitly avoids collapsing sibling subagents:src/server/request-log-conversation.ts:64-83opencode-go-2.registryEntryForProviderDestinationis already used by the quota path for this exact alias/destination problem.ocx_plus 32 hex characters). This mirrors the existingderiveXaiConvIdprivacy pattern without sending the raw internal ID.provider.headers, allowing the existing Chat/Responses adapters and explicit wire overrides to carry it.promptCacheKeyfallback should only be used when it is known not to represent a shared cohort.This should not be implemented as a registry
staticHeadersvalue: a global static session ID would merge every conversation into one upstream affinity group. An analogous client bug documents that failure mode: earendil-works/pi #4847.Acceptance criteria / tests
Risks / additional context
kimi-k2.7-codeshard problem where a particular session ID consistently selects a failing replica. This is an upstream sticky-routing defect, not a reason to send a random value or omit a now-required header. A new conversation provides a different affinity key as a temporary workaround.Checks
lidge-jun commentedon Sep 3, 2026
Closing in favor of #3378, which tracks both OpenCode Go wire-contract defects together.
Thank you @colthreepv — your report on the missing
x-opencode-sessionheader was accurate and reproducible.Verified. Confirmed: the
opencode-goregistry row insrc/providers/registry.tsdefines no session-header behavior, andx-opencode-sessiondoes not appear anywhere undersrc/.This is grouped with the other open
opencode-godefect because both have the same cause — a provider-specific wire requirement the adapter does not represent — and fixing them in one pass avoids a second round of the same investigation. #3378 names this issue and credits you.Please follow #3378 for the fix.