Skip to content

custom primary agent denied free-tier (can only be used from within OpenCode) while built-in plan works with identical model #53347

Closed as not planned

Description

@Redaessa7

Description

Custom primary agent (orchestrator, mode: primary) gets Error from provider (Console): OpenCode's free tier can only be used from within OpenCode on its own requests, while built-in plan works with the identical free model in the same run — before any subagent is spawned. Log shows agent=orchestrator mode=primary → 403 vs agent=plan mode=primary → success, same provider/model/session mode. Even the small/title model fails under the custom agent.

Plugins

none

OpenCode version

Desktop v1.18.34

Steps to reproduce

  1. Define a custom primary agent in opencode.json (no model override, inherits free model).
  2. Select muse-spark-1.3-contributor-free and send any message with that agent.
  3. Same message with built-in plan agent succeeds.

Screenshot and/or share link

From opencode.log (same run):

  • agent=orchestrator mode=primary → ERROR ... FreeTierError 403
  • agent=plan mode=primary → INFO ... stream success

Operating System

Windows (Desktop app)

Terminal

OpenCode Desktop (Electron)

Activity

  1. Redaessa7 commented on Oct 5, 2026

    @Redaessa7
    Author

    Updated the body to follow the Bug report template (Description / Plugins / OpenCode version / Steps to reproduce / Screenshot / OS / Terminal). Please re-check compliance.

  2. github-actions commented on Oct 5, 2026

    @github-actions
    Contributor

    Thanks for updating the issue to use the Bug Report template and adding reproduction details. It now meets the issue requirements.

  3. l7feng commented on Oct 5, 2026

    @l7feng

    Same symptom, same version (Desktop v1.18.34). I captured the actual outgoing headers for both a passing and a failing request, and I can rule out the User-Agent / client-identity explanations for this path.

    How I captured them (no MITM)

    The x-opencode-* headers are only attached when providerID.startsWith("opencode"), so a custom provider never receives them. Instead, override the built-in opencode provider and point it at a local listener — providerID stays opencode, so the branch still fires:

    {
      "$schema": "https://opencode.ai/config.json",
      "provider": { "opencode": { "options": { "baseURL": "http://127.0.0.1:8787/v1" } } }
    }
    OPENCODE_CONFIG_DIR=<isolated copy> opencode run --agent <name> -m opencode/big-pickle --dir <tmp> "hi"

    Then dump req.headers in the listener. No TLS interception, no config change to the real install.

    Result: byte-identical identity headers

    header passing request failing request
    user-agent opencode/1.18.32 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14 identical
    x-opencode-client desktop identical
    x-opencode-project global identical
    x-opencode-session ses_ef2d56ee… ses_ef2db43e…
    x-opencode-request msg_10d2a91a… msg_10d24bcb…

    All four documented identity headers (User-Agent, x-opencode-client, x-opencode-session, x-opencode-request) are present and well-formed on both. The only differences are the session/message IDs, which necessarily differ.

    ⇒ For the direct client path, neither the User-Agent nor the client identity can explain a pass/fail split. A "missing header" explanation does not fit here.

    The only substantive difference is the request body — 43413 B vs 2444 B, i.e. the system prompt plus tool definitions.

    That points at the tool/permission cluster instead

    This lines up with the other open reports where the trigger correlates with agent-level tool configuration rather than model or session:

    My failing agent is a custom agent with no model override and permission entries denying bash, webfetch, websearch and task. Its title/small request in the same session also went through, which matches the "even the small/title model fails under the custom agent" observation here.

    Caveats, stated honestly

    • I cannot prove causality. Body size is a confounded signal: my "passing" capture was the small/title request, so the 43413 B vs 2444 B gap conflates agent identity with request size.
    • What is conclusive is the negative result: identity headers are identical, so they are not the discriminator.
    • The failure reproduces on the standalone CLI too (opencode-ai 1.18.32 via npm), independently of the desktop app — consistent with Zen free models fail with FreeTierError in official CLI 1.18.34 (Linux) #52907.

    Client-side, this looks unfixable from config; the heuristic is server-side and not published.

  4. Redaessa7 commented on Oct 6, 2026

    @Redaessa7
    Author

    Confirming from the reporter's side: this matches the tool/permission-cluster theory. The failing custom primary agent (orchestrator) has edit: deny, �ash: deny, a ask allowlist (5 subagents), and emperature: 0.2 — no model override. The built-in plan agent that succeeds in the same run has no such custom permission block. So the discriminator here correlates with custom agent permissions, not the agent name or identity headers. Happy to provide the full agent definition or a minimal repro (custom primary with �ash: deny only) if it helps isolate the trigger.

  5. Redaessa7 commented on Oct 7, 2026

    @Redaessa7
    Author

    Correction to my earlier findings: the 'agent name is the trigger' conclusion was WRONG. Root cause of my misleading ladder test: the Desktop client caches agent definitions — none of my permission edits took effect until a full app quit/reopen, so every probe ran against the original config. Confirmed result after proper restarts: �ash: deny on ANY custom agent (primary or subagent) triggers the FreeTierError; flipping to �ash: allow fixes it (verified on the orchestrator itself). Currently testing �ash: ask as the safe middle ground. Two takeaways for the fix: (1) the gate correlates with bash-deny on custom agents, and (2) agent-definition caching until restart makes this painful to diagnose — a 'reload agents' action or a startup log line would help.

  6. Redaessa7 commented on Oct 7, 2026

    @Redaessa7
    Author

    Confirmed root cause + workaround (verified with restarts)

    Root cause is \�ash: deny\ on ANY custom agent (primary or subagent) — flipping to \�ash: allow\ fixes it, confirming @l7feng's permission-cluster theory. My earlier 'agent name is the trigger' conclusion was wrong (see below).

    Safe middle ground (tested live): \�ash: ask\ also passes the gate AND shows a real approval prompt before each command — applied to orchestrator, docs-keeper and reviewer in our repo, all green, safety preserved.

    Diagnostic note (verified by repeated testing, not documented)

    The client caches agent definitions — permission edits had zero effect until a full app quit/reopen (this silently invalidated my whole first test ladder: 6 permission variants, all run against stale config). The docs state nothing about this; related open requests: #8751 (hot-reload agents/skills/commands), #6815 (reload-config action), #39987 (config changes need full restart). Suggest either honoring agent edits without restart, or at minimum a reload-agents action + a log line when cached defs are used.

    Leaving this open for a proper upstream fix (clearer error, documented restriction) — this comment is only the client-side workaround.

  7. 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

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