Skip to content

[Provider]: Union Alpha inference fails on OpenCode routes; per-model Anthropic protocol mismatch #4847

Closed

Description

@carbonimax

Client or integration

Codex App; also reproduced with minimal direct HTTP requests.

Provider or upstream service

OpenCode / Union Alpha (union-alpha). Reproduced on opencode-go; the same failure is observed on opencode-zen. Please also consider the shared model protocol metadata for opencode-free (related catalog issue #4826).

OpenCodex version

2.57.0 (installed CLI). macOS, Apple Silicon. Observed September 16, 2026.

Endpoint or capability

Outbound protocol selection: /zen/go/v1/chat/completions versus /zen/go/v1/messages; corresponding Zen /zen/v1 routes. Inbound Codex Responses requests and minimal Chat Completions requests.

Current behaviour

Union Alpha works in the OpenCode application but fails through OpenCodex with upstream_server_error / HTTP 500. Local OpenCode history confirms successful responses for provider opencode-go, model union-alpha; it is not merely a different model selected under the “Free” display name.

Both clients use the same configured Go base URL and credential (equality checked locally; no credentials included). OpenCodex config uses provider-wide adapter: openai-chat. The local OpenCode model catalog instead specifies a per-model override for Union Alpha: provider.npm: @ai-sdk/anthropic, although the provider default is OpenAI-compatible.

The displayed proxy error alone does not prove an internal OpenCodex crash: a minimal direct Chat Completions request also returns 500. This points toward a protocol/request compatibility issue; it does not establish the full root cause.

Expected behaviour

Select the upstream protocol supported by Union Alpha without changing the adapter for other models on the same provider. Preserve the distinction between model availability, upstream service failures and proxy failures. Clarify any documented client/session requirements rather than assuming every model at a mixed-protocol gateway accepts Chat Completions.

The application/catalog evidence supports investigating the Anthropic Messages path; successful generation through that path has not yet been validated in the direct reproduction below.

Minimal redacted request or reproduction

# Local proxy, configured with opencode-go and its normal API key.
# No secrets or private prompt content are included in this request.
curl http://127.0.0.1:10100/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"opencode-go/union-alpha","messages":[{"role":"user","content":"Reply only OK."}],"max_tokens":32,"stream":false}'

Observed comparison using the same credential and Go base URL:

  1. Direct POST /zen/go/v1/chat/completions, minimal message, no reasoning field: 500.
  2. Same direct call with reasoning_effort: max: 500.
  3. Equivalent minimal request through OpenCodex: 500.
  4. Direct POST /zen/go/v1/messages with x-api-key, anthropic-version: 2023-06-01, and no session header: 400 MissingSessionID.
  5. Add a fresh diagnostic x-opencode-session value: 503 Endpoint is unavailable.
  6. Chat Completions with that same diagnostic session header still returns 500.

A first Python HTTP-client attempt received a separate 403/1010 response; direct comparisons above were repeated using Node fetch to avoid conflating that client-specific rejection with the 500s.

Actual response or error

Proxy:

{"error":{"message":"Provider error 500: Internal server error","type":"server_error","code":"upstream_server_error"}}

Direct Chat Completions:

{"error":{"type":"error","message":"Internal server error"}}

Direct Messages without session header:

{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console Go): Request is missing x-opencode-session and cannot be routed efficiently. Please see https://opencode.ai/docs/go/#where-can-i-use-it"}}

Direct Messages with diagnostic session header:

{"type":"error","error":{"type":"api_error","message":"Error from provider (Console Go): Upstream request failed: Endpoint is unavailable."}}

Both low and max reasoning requests have failed through the proxy; this is not isolated to max. Two benchmark attempts failed before editing any files. The harness produced repeated 500s; no benchmark score was attributed to the model.

Upstream documentation

https://opencode.ai/docs/zen/
https://opencode.ai/docs/go/#where-can-i-use-it

Suggested mapping or implementation notes

Investigate a per-model protocol override for union-alpha across the OpenCode provider entries, based on upstream model metadata. Do not switch the entire mixed-model provider to Anthropic. Check documented authentication/session requirements and reasoning translation, and add regression coverage that leaves existing Chat Completions models unchanged.

This is a diagnostic hypothesis, not a tested patch. The 503 on the Messages path still requires investigation. No request to bypass upstream access restrictions is intended.

Additional context and attachments

Related: #4826, which primarily reports exclusion from the opencode-free catalog and also mentions the protocol mismatch. That issue was closed automatically for template formatting; this report follows the provider compatibility template and focuses on inference failures. It does not claim #4826 has been fixed.

No global configuration was changed during the comparison. Exact endpoint reproduction was performed for Go; Zen is a separate observed failure, and Free was not independently inference-tested in this investigation. No proposed PR yet.

Checks

  • I searched existing provider compatibility issues.
  • The request and response examples are redacted.
  • The expected behaviour is based on upstream specification or a concrete client requirement.

Activity

  1. added
    catalogModel catalog, slugs, visibility, routed entries
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Sep 16, 2026
  2. lidge-jun commented on Sep 16, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 72 / 80

    이 이슈는 OpenCode Go/Zen 쪽 Union Alpha(union-alpha)가 OpenCodex를 거치면 Chat Completions로 500(upstream_server_error)이 나고, 같은 키·같은 Go base URL로 직접 쳐도 Chat는 500, Anthropic Messages는 세션 헤더 없으면 MissingSessionID, 넣으면 503이라는 보고다. 보고자는 OpenCode 앱 로컬 카탈로그가 Union Alpha만 provider.npm: @ai-sdk/anthropic으로 두고 나머지는 OpenAI 호환 기본값을 쓴다고 적었다. 즉 "프로바이더 전체를 Anthropic으로 바꾸라"가 아니라, 모델 하나만에 프로토콜 예외가 필요하다는 진단이다. 관련 #4826(opencode-free 카탈로그 제외)은 템플릿 형식으로 이미 닫혔고, 이 이슈는 추론 실패에 초점을 맞춘 provider-compatibility 보고라서 중복으로 닫을 대상은 아니다.

    지금 dev HEAD 8c5917448e971f8bbfb7595252932f678b486a35(package 2.58.0)를 보면 방향이 맞는지 바로 확인할 수 있다. src/providers/registry/entries-core.ts의 opencode-go 행은 프로바이더 기본 어댑터가 openai-chat이고, baseUrl은 https://opencode.ai/zen/go/v1이다. 이미 혼성 와이어를 modelWireDefaults로 다루는 선례가 있다. gpt-5.6-luna / grok-4.6 / muse-spark-1.3-contributor 등은 openai-responses로 핀한다. 또 src/types/wire.ts의 ANTHROPIC_WIRE_MODELS["opencode-go"]에는 minimax-m2.5/minimax-m2.7/minimax-m3만 들어 있다. union-alpha는 생성 메타데이터(src/generated/model-metadata.ts opencode-go 목록)에도, 위 예외 목록에도 없다. 그래서 기본 경로는 Chat Completions로 나가며, 보고된 직접 curl 500과 같은 프로토콜 불일치가 재현될 여지가 크다.

    다만 "Anthropic으로만 바꾸면 끝"은 아직 증명되지 않았다. 본문 재현 4·5번이 Messages 경로에서 세션/엔드포인트 거절을 보여 주고, OpenCodex가 x-opencode-session을 임의로 위장 발급하지 않는 정책은 opencode-free note(entries-extended.ts)에도 이미 적혀 있다. 또한 src/types/wire.ts의 MODEL_ADAPTER_OVERRIDE_ALLOWED는 지금 openai-chat과 openai-responses만 허용한다. 사용자가 modelAdapters.union-alpha = "anthropic"을 써도 src/server/adapter-resolve.ts의 resolveWireProtocolOverride가 그 값을 채택하지 않는다. Anthropic 핀은 레지스트리 ANTHROPIC_WIRE_MODELS(또는 동등한 하드 핀) 확장으로만 열린다. types.ts/config.ts 분리 캠페인과 무관하므로 "닫고 리베이스" 대상이 아니다.

    경로/심볼 - src/providers/registry/entries-core.ts opencode-go — 기본 adapter: "openai-chat". union-alpha용 modelWireDefaults/ANTHROPIC_WIRE_MODELS 항목 없음.
    경로/심볼 - src/types/wire.ts MODEL_ADAPTER_OVERRIDE_ALLOWED — anthropic 미포함. 설정만으로 Anthropic 전환 불가.
    경로/심볼 - src/types/wire.ts ANTHROPIC_WIRE_MODELS["opencode-go"] — minimax 세 개만. Union Alpha 가설을 코드에 심을 자리.
    경로/심볼 - src/server/adapter-resolve.ts resolveWireProtocolOverride — pin → modelAdapters → modelWireDefaults → provider adapter 순서. anthropic은 pin/레지스트리 경로여야 함.
    경로/심볼 - src/providers/opencode-go-transport.ts / Zen rate-limit — 세션·업로드 거절과 겹치면 Messages 전환만으로 503이 남을 수 있음. 본문 재현 5번과 맞춰 봐야 한다.
    관련 - #4826은 카탈로그 제외·템플릿 닫힘. 이 이슈는 추론 실패라서 별개로 유지하는 편이 맞다.

    메인테이너의 판단이 필요한 지점

    • Union Alpha를 ANTHROPIC_WIRE_MODELS에 넣을지, 아니면 먼저 Messages 경로가 세션 없이도(또는 문서화된 제3자 세션 계약으로) 200을 내는지 증거부터 모을지
    • Chat 500이 프로토콜 불일치인지, upstream 일시 장애/쿼터인지 구분하는 최소 재현을 CI fixture로 둘지
    • opencode-zen/opencode-go/opencode-free에 같은 모델 id가 있을 때 예외를 프로바이더별로 복제할지, destination 공통 메타로 올릴지

    너의 추천
    이슈는 열어 두고, 다음 PR은 "가설 확정"부터 하라. (1) 직접 Messages로 Union Alpha가 정상 생성되는지(세션 요구 포함) redacted 증거를 이슈에 한 번 더 붙이고, (2) 증거가 서면 ANTHROPIC_WIRE_MODELS["opencode-go"]에 union-alpha를 추가하는 작은 레지스트리 PR을 열어라. 프로바이더 전체를 Anthropic으로 바꾸거나 세션 헤더를 위장 발급하는 방향은 추천하지 않는다. Chat만 고치려다 Responses/minimax 예외 선례를 깨지 않도록 회귀 테스트에 "다른 Go 모델은 여전히 chat/responses 기본"을 넣어라.

    이 댓글은 grok-bot이 작성했습니다

  3. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    Owner

    Closed by #4930 on dev, squashed as d20b25d47068e6b2a40fe561d6ca8ed449046df7.

    Your diagnosis held: this needed a per-model protocol exception, not a provider-wide adapter change. union-alpha's exact model id is now pinned to the Anthropic wire for opencode-go, and sibling Chat and Responses models on the same provider are untouched.

    Two things surfaced while fixing it that your reproduction had already half-exposed. Generated x-opencode-session values were not namespaced by wire protocol, so a lane could carry a session minted under a different protocol — that is now namespaced with a versioned hash separator, and an operator-supplied header still wins unchanged. Separately, destination recognition was sensitive to wire-selection order: once the wire flipped to Anthropic, the registry matcher no longer recognized the already-flipped provider. Each request now retains the original routed provider for the registry check and settles the final wire separately.

    On the part that is not ours: step 5 of your reproduction still reproduces. A direct Messages call with a fresh session header returns 503 Endpoint is unavailable, and that is upstream service availability, not protocol selection. This change does not establish successful Union Alpha inference, and saying otherwise would be a claim the evidence does not support. What it does deliver is the expected behaviour you asked for — the upstream protocol Union Alpha declares is now the one selected, and model availability, upstream failures and proxy failures stay distinguishable rather than collapsing into a single 500.

    If inference still fails once the Go endpoint is serving again, that is a new report rather than this one, and the trace will now name which of the three it is. Shipping in the next release off dev.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    catalogModel catalog, slugs, visibility, routed entriesproviderProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reports

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions