Skip to content

Server (1.18.31): Free tier zen models fail - User-Agent not forwarded to zen API #49756

Closed as not planned

Description

@iagorobo24-hub

Bug Report

Versión: opencode 1.18.31 (latest)
Plataforma: Linux (Ubuntu 22.04)

Descripción

El servidor opencode (opencode serve / puerto 4096) no reenvía el header User-Agent cuando hace peticiones a la API zen (https://opencode.ai/zen/v1/...). Esto hace que el tier gratuito de modelos zen falle con error 403:

Error from provider (Console): OpenCode's free tier can only be used from within OpenCode

Impacto

  • TUI (opencode / iago-opencode) → Fallan modelos zen gratuitos
  • CLI run (opencode run -m muse-spark-1.3-contributor-free) → Fallan modelos zen gratuitos
  • openchamber (web UI) → Fallan modelos zen gratuitos
  • Cualquier cliente que use la API del servidor (opencode serve) → Fallan modelos zen gratuitos

Comportamiento esperado vs actual

Componente Esperado Actual
Servidor opencode → zen API Incluye User-Agent: opencode/1.18.31 No incluye User-Agent
Tier gratuito zen Funciona 403 Forbidden

Root Cause

El servidor opencode actúa como proxy hacia la API zen. Cuando recibe una petición de /api/session/{id}/message con modelo zen, hace la petición a https://opencode.ai/zen/v1/chat/completions sin incluir el header User-Agent que la API zen ahora requiere para el tier gratuito.

Workaround parcial (openchamber)

En openchamber 1.24.1 agregué el header en el proxy:

proxyReq.setHeader('user-agent', 'opencode/1.18.31');

Esto hace que openchamber → servidor opencode funcione, pero el servidor → zen API sigue fallando porque el binario no reenvía el header.

Bug adicional relacionado

El endpoint POST /api/session/{id}/message del servidor devuelve HTML (página web UI) en lugar de JSON cuando falla, rompiendo todos los clientes API.

Request

Que el servidor opencode incluya automáticamente User-Agent: opencode/<version> en todas las peticiones salientes a la API zen (y idealmente a todos los proveedores que lo requieran).

Logs relevantes

# Petición que falla (desde servidor opencode a zen API)
POST https://opencode.ai/zen/v1/chat/completions
# Headers faltantes: User-Agent: opencode/1.18.31

# Respuesta:
403 Forbidden
{\"type\":\"error\",\"error\":{\"type\":\"FreeTierError\",\"message\":\"Error from provider (Console): OpenCode's free tier can only be used from within OpenCode\"}}

Configuración probada (no funciona)

{
  \"$schema\": \"https://opencode.ai/config.json\",
  \"provider\": {
    \"opencode\": {
      \"headers\": {
        \"User-Agent\": \"opencode/1.18.31\"
      }
    }
  }
}

Incluso configurando headers en provider.opencode, el servidor no los reenvía a la API zen.

Activity

  1. iagorobo24-hub commented on Sep 24, 2026

    @iagorobo24-hub
    Author

    Bisection results (opencode 1.18.32, server mode)

    Tested same prompt + same zen model (opencode/big-pickle, correct model: {providerID, modelID} body) against local opencode serve, fresh session each time:

    Server config Agent Result
    Vanilla, bash/glob/grep/read: allow, no profile build (built-in) ✅ 200, real answer, cost 0
    Vanilla + task/bash/read: deny build (built-in) ❌ 403 FreeTierError
    Vanilla + only task: deny build (built-in) ❌ 403 FreeTierError
    Profile iago-dev (task: allow, tool denys, custom agents) build (custom, edit/write/bash: deny) ❌ 403
    Same profile coder (allows bash *, edit, write) ✅ 200, real answer
    Same profile explore (edit/write deny, read-only bash allows) ✅ 200, real answer

    Additional notes:

    • opencode auth login --provider opencode (credential present, server restarted, new session) does not fix it.
    • Removing custom provider/models overrides from the profile does not fix it.
    • The failing agent doesn't matter for routing: request reaches https://opencode.ai/zen/v1/responses and Cloudflare returns the 403 — so the Console-side "within OpenCode" check seems to key off the agent's permission footprint (fully tool-denied agents like build/background agents fail; agents with any tool access pass).
    • Related: POST /session/:id/message with top-level modelID (instead of model: {providerID, modelID}) is silently ignored and falls back to the default model — worth a validation error instead.

    This matches @Hdiaktoros's report in #49680 (custom subagent with permission block fails, same prompt without it works).

  2. l7feng commented on Oct 5, 2026

    @l7feng

    Useful data point that narrows the scope of this one: on the direct client path the User-Agent is forwarded, in both the desktop app and the standalone CLI.

    Measured on Desktop 1.18.34 (Windows) and opencode-ai 1.18.32 (npm), by pointing the built-in opencode provider at a local listener and dumping req.headers:

    user-agent:         opencode/1.18.32 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14
    x-opencode-client:  desktop
    x-opencode-project: global
    x-opencode-session: ses_…
    x-opencode-request: msg_…
    

    Two things worth separating here:

    1. This looks specific to the opencode serve proxy path. Your report is about clients going through the server. When opencode itself talks to Zen, the header is present — so the "server does not re-forward" mechanism you describe doesn't appear to apply to the in-process/direct path. That makes your repro (and the openchamber workaround) look like a genuinely separate bug rather than a general one.

    2. The wire value is not exactly opencode/<semver>. The client defines two UA constants:

    • `opencode/${InstallationVersion}` — this is the one attached to the request carrying the x-opencode-* headers
    • `opencode/${InstallationChannel}/${InstallationVersion}/${Flag.OPENCODE_CLIENT}`

    but on the wire the AI SDK provider-utils and the Bun runtime append extra tokens, so what actually goes out is:

    opencode/1.18.32 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14
    

    I want to be clear that this is not the cause of the 403 I hit — a passing request and a failing request carried byte-identical user-agent, x-opencode-client and x-opencode-project. So whatever the gateway matches on, it is not distinguishing those two requests by UA here.

    I'm raising it only because if the gate ever moves to a strict match on opencode/<semver>, the extra suffixes would break it independently — and a config-level provider.opencode.headers.User-Agent override (which you already found ineffective on the server path) would be the obvious thing to try pinning the value exactly.

    For the 403 itself, my captured evidence suggests the differentiator is the request body (system prompt + tool definitions) rather than any header — see #53347, where a passing and a failing request in the same session are header-identical.

  3. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions