Skip to content

opencode-free: Zen rejects requests without x-opencode-session (free tier lock-in) #4121

Closed

Description

@Hydroxide8006

Client or integration

Direct HTTP client

Provider or upstream service

opencode-free (https://opencode.ai/zen/v1)

OpenCodex version

2.10.2

Endpoint or capability

/v1/chat/completions (free models, e.g. mimo-v2.5-free)

Current behaviour

Requests via the opencode-free provider fail on free models. Upstream returns:

{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}}

The proxy currently only sends x-opencode-client: desktop (see opencode-free entry in src/providers/registry.ts), which is not sufficient for the Zen free-tier gate.

Expected behaviour

Free-model requests through opencode-free should succeed (HTTP 200, usage with cost 0), matching what the real OpenCode client gets when it sends its session headers.

Minimal redacted request or reproduction

# 1. Direct upstream repro (no keys involved, keyless free tier):
# Fails - same error the proxy currently triggers:
curl -s -X POST https://opencode.ai/zen/v1/chat/completions   -H 'Content-Type: application/json'   -H 'x-opencode-client: desktop'   -d '{"model":"mimo-v2.5-free","messages":[{"role":"user","content":"say ok"}],"max_tokens":1}'

# Passes - adding any x-opencode-session value clears the gate:
curl -s -X POST https://opencode.ai/zen/v1/chat/completions   -H 'Content-Type: application/json'   -H 'x-opencode-client: desktop'   -H 'x-opencode-session: ses_test123000000000000000001'   -H 'User-Agent: opencode/1.18.30'   -d '{"model":"mimo-v2.5-free","messages":[{"role":"user","content":"say ok"}],"max_tokens":1}'

# 2. Through the proxy:
# ocx start (default port 10100), provider opencode-free configured, then:
curl -s -X POST http://127.0.0.1:10100/v1/chat/completions   -H 'Content-Type: application/json'   -d '{"model":"opencode-free/mimo-v2.5-free","messages":[{"role":"user","content":"say ok"}],"max_tokens":5}'
# Before fix: MissingSessionID error. After adding x-opencode-session to
# providers.opencode-free.headers in config + restart: HTTP 200.

Actual response or error

{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}}

Probe matrix (all redacted, no credentials):

  • bare request -> MissingSessionID
  • x-opencode-client only -> MissingSessionID
  • User-Agent opencode/1.18.30 only -> MissingSessionID
  • x-opencode-session set to any value (even unformatted) -> gate passed (200 or quota error, never MissingSessionID)

So the gate checks presence of x-opencode-session, not User-Agent and not session format.

Upstream documentation

No public specification exists for these headers; they were reverse-engineered from the opencode-ai binary (v1.18.30). For providerID starting with "opencode" it sends: x-opencode-project (optional), x-opencode-session (ses_...), x-opencode-request (msg_...), x-opencode-client, User-Agent opencode/. Zen docs: https://opencode.ai/docs/zen/

Suggested mapping or implementation notes

In the openai-chat adapter (or a Zen-specific wrapper) when baseUrl is https://opencode.ai/zen/v1, generate per request:

  • x-opencode-session: ses_ (fresh per request)
  • x-opencode-request: msg_ (fresh per request)
  • User-Agent: opencode/ (only if caller did not set one)
  • keep existing x-opencode-client: desktop

Per-request generation mirrors the real client. A static session ID in config works today but risks future per-session rate-limiting.

Additional context and attachments

Related: free-tier gate appears new (previously x-opencode-client alone was enough). Note on the earlier lock-in error string: it is returned with error type MissingSessionID, which is what pointed at the session header.

Checks

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

Activity

  1. github-actions commented on Sep 9, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  2. Ingwannu commented on Sep 9, 2026

    @Ingwannu
    Owner

    I can confirm that the current opencode-free preset does not generate a session ID. I have not run the live free-tier probes in this report.

    There is a support/authorization question before implementing the suggested headers. Zen's public docs advertise use with other coding agents generally, but describe the promotional free models as available on OpenCode; your reported upstream error explicitly restricts this tier to OpenCode. The documentation does not establish that fabricating session identifiers or a versioned OpenCode User-Agent is a supported third-party integration. Source: https://opencode.ai/docs/zen/ (checked 2026-09-09).

    Please obtain an upstream-supported third-party integration contract or clarification for this exact keyless tier. Until then I will not add client impersonation or rotate synthetic sessions to get past its admission gate. A safe OCX change can explain the upstream restriction accurately and direct users to an upstream-supported account/provider path. Keeping this open for clarification rather than treating HTTP 200 from a fabricated header as authorization.

  3. lidge-jun commented on Sep 9, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 48 / 80

    이 이슈는 keyless opencode-free(Zen https://opencode.ai/zen/v1)로 무료 모델(mimo-v2.5-free 등)을 치면, 업스트림이 MissingSessionID / “OpenCode's free tier can only be used in OpenCode”로 거절한다는 내용입니다. 지금 레지스트리는 x-opencode-client: desktop과 User-Agent: opencode만 넣고(src/providers/registry.ts opencode-free staticHeaders, 약 3023–3035행), 리포트에 따르면 x-opencode-session이 있어야 게이트가 열립니다. curl 재현(세션 헤더 없음 실패 / 임의 세션 값 있으면 통과)이 분명합니다.

    현재 dev에는 이미 OPENCODE_GO_SESSION_HEADER = "x-opencode-session"(src/providers/opencode-go-transport.ts)와, 요청에 세션이 있으면 그대로 전달하는 경로(src/server/chat-completions.ts 253–254행, Claude messages 쪽도 유사)가 있습니다. 문제는 클라이언트가 세션을 안 보내면 프록시가 free 티어용 세션을 만들어 붙이지 않는다는 점입니다. Go 쪽 affinity와 free-tier lock-in은 겹치지만 목적이 다릅니다. 전자는 같은 대화 유지, 후자는 “OpenCode 안에서만 free” 정책 우회에 가깝습니다. 버전 표기가 2.10.2로 오래됐어도, HEAD 레지스트리 헤더 조합은 리포트와 같은 형태라 재현 가능성은 남아 있습니다.

    우선순위는 중간 이하로 두는 편이 맞습니다. 지금은 2.50.0 / 안정 2.49.0 출고·overflow·계정 풀 건강(#4120/#4140)·서비스 업데이트(#4141)가 더 급하고, 이 이슈는 업스트림 정책·ToS 회색지대입니다. 임의의 ses_…를 프록시가 자동 주입하면 “OpenCode 전용 free” 가드를 우회하는 셈이 되어 유지·법적/관계 리스크가 있습니다. 반대로 헤더를 안 넣으면 free 모델이 계속 깨져 featured keyless 진입점이 실망을 줍니다. 문서에 “무료 티어는 공식 OpenCode 클라이언트 세션이 필요할 수 있다”고 쓰고, 자동 위조 세션은 넣지 않는 선택도 있습니다.

    src/providers/registry.ts (opencode-free staticHeaders) - client/UA만 있음. 세션 없음 → MissingSessionID
    src/providers/opencode-go-transport.ts (OPENCODE_GO_SESSION_HEADER) - 헤더 이름은 이미 있음. free 자동 주입은 별 정책 결정
    src/server/chat-completions.ts (세션 passthrough) - 클라이언트가 준 값만 전달. 없으면 생성 안 함
    업스트림 정책 - 임의 세션 주입은 lock-in 우회. 제품/관계 판단 필요
    이슈 버전 2.10.2 - HEAD에서 curl로 한 번 더 재현 확인 권장

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

    • 자동으로 합성 x-opencode-session을 넣을지, 문서/에러 메시지만 개선할지, free 모델을 카탈로그에서 내릴지
    • OpenCode/Zen 쪽에 “프록시·브로커 허용” 공식 입장이 있는지
    • Go session affinity 로직과 free-tier 헤더를 한 구현으로 묶을지 말지(묶으면 책임이 커짐)
    • help wanted로 둘지, needs-design/정책 보류로 라벨할지

    너의 추천
    바로 합성 세션을 넣는 PR은 받지 말고, HEAD에서 재현만 확인한 뒤 (1) 에러를 사람이 읽게 보강하거나 (2) 노트에 free 티어 제한을 명시하거나 (3) 업스트림 허용 범위가 확인되면 그때 최소 헤더 패치를 열어라. 중복 이슈·types 분할 무관. 급하면 #4140/#4141 뒤에 두라.

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

  4. added 2 commits that reference this issue on Sep 9, 2026
    9152450
    6578cab
  5. lidge-jun commented on Sep 9, 2026

    @lidge-jun
    Owner

    Landed via #4136 at 9152450

  6. RHODIZSECURITY commented on Sep 14, 2026

    @RHODIZSECURITY
    Contributor

    Revalidated on OpenCodex 2.54.0 (Linux, 2026-09-14): a combo that still included opencode-free/nemotron-3-ultra-free reached the keyless Zen route after earlier targets were unavailable and received the same terminal MissingSessionID / OpenCode's free tier can only be used in OpenCode response. This confirms the upstream gate still applies.

    Local mitigation was deliberately fail-closed: remove/disable opencode-free from automatic combo routing rather than fabricate x-opencode-session; keep supported keyed OpenCode routes as separate targets. No spoofed OpenCode client identity is being used.

  7. added 2 commits that reference this issue on Sep 17, 2026
    eb9f98e
    f44d672
  8. fehmi commented on Sep 19, 2026

    @fehmi

    Can't use Zen or this opencode-free bcs of "can only be used in OpenCode" response

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

    landed-via-maintainerOriginal PR closed after landing via a maintainer merge trainproviderProvider 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