Skip to content

[Bug] OpenCode free tier models returning 403 FreeTierError via 9router proxy #4101

Open

Description

@LustHK

Description

OpenCode free tier models (mimo-v2.5-free, muse-spark-1.2-contributor-free) started returning 403 FreeTierError when accessed through 9router proxy. This started approximately 15 minutes ago (Sep 16, 2026 ~20:55 UTC-3). The models were working fine for weeks before this.

Error Log

20:55:50 🟢 ▶ POST oc/mimo-v2.5-free → opencode/mimo-v2.5-free · FMT: openai→openai · STREAM · 2 MSG · 38 TOOL · ACC:Public
20:55:50 ℹ️ PROXY OPENCODE | mimo-v2.5-free | conn=Public | pool=*** | vercel-relay=https://elysium-hw3a89h6n-elysium13.vercel.app
20:55:50 🔵 ▶ POST oc/mimo-v2.5-free → opencode/mimo-v2.5-free · FMT: openai→openai · JSON · 2 MSG · ACC:Public
20:55:51 🔵 ✗ ERROR 403 · opencode/mimo-v2.5-free · 779ms URL: https://opencode.ai/zen/v1/chat/completions 403: {"type":"error","error":{"type":"FreeTierError","message":"Error from provider (Console): OpenCode's free tier can only be used from within OpenCode"}}
20:55:53 🟢 ✗ ERROR 403 · opencode/mimo-v2.5-free · 2196ms URL: https://opencode.ai/zen/v1/chat/completions 403: {"type":"error","error":{"type":"FreeTierError","message":"Error from provider (Console): OpenCode's free tier can only be used from within OpenCode"}}
20:55:53 🟢 ▶ POST oc/muse-spark-1.2-contributor-free → opencode/muse-spark-1.2-contributor-free · FMT: openai→openai-responses · STREAM · 1 MSG · 38 TOOL · ACC:Public
20:55:53 🟢 ✗ ERROR 403 · opencode/muse-spark-1.2-contributor-free · 420ms URL: https://opencode.ai/zen/v1/responses 403: {"type":"error","error":{"type":"FreeTierError","message":"Error from provider (Console): OpenCode's free tier can only be used from within OpenCode"}}

Environment

  • 9router version: latest
  • Models affected: oc/mimo-v2.5-free, oc/muse-spark-1.2-contributor-free
  • Provider: opencode (via opencode.ai/zen/v1)
  • Connection: Public

Additional Context

  • These models were working fine through 9router for weeks before this error started.
  • The error suggests OpenCode added server-side validation to ensure free tier models can only be accessed from the official OpenCode client.
  • This seems to be a new restriction deployed by OpenCode in the last ~15 minutes.
  • Other users may be affected by this change.

Expected Behavior

Free tier models should continue to work through the 9router proxy as they did before.

Actual Behavior

All free tier models return 403 with FreeTierError: OpenCode's free tier can only be used from within OpenCode.

Activity

  1. arwinwijaya commented on Sep 17, 2026

    @arwinwijaya

    i have same issue

  2. anojndr commented on Sep 17, 2026

    @anojndr
    Contributor

    Identified the root cause of this error:

    OpenCode upstream deployed two server-side validation checks on free tier endpoints (/zen/v1/chat/completions and /zen/v1/responses) when using Authorization: Bearer public:

    1. User-Agent Header: Upstream requires User-Agent: opencode/<version> with version >= 1.17.0. Bare opencode or third-party client user agents trigger 403 FreeTierError (and versions < 1.17.0 receive 426 Upgrade Required). 9router was defaulting to bare User-Agent: opencode.
    2. Session Header (x-opencode-session): Upstream enforces OpenCode's canonical descending identifier format: ses_ + 12 hex timestamp characters + 14 Base62 characters (/^ses_[0-9a-f]{12}[0-9A-Za-z]{14}$/, 30 characters total). Missing headers or raw UUID formats trigger 403 FreeTierError.

    Fix submitted in PR #4105:

    • Defaults User-Agent to opencode/1.18.31 and validates downstream client versions.
    • Generates canonical OpenCode session IDs and deterministically translates downstream client sessions into valid OpenCode session format to preserve prompt caching and session affinity.
    • Eliminates mutable shared instance state on OpenCodeExecutor for safe concurrent request handling.
  3. added a commit that references this issue on Sep 17, 2026
    94fdb6b
  4. added a commit that references this issue on Sep 17, 2026
    c12e263
  5. LustHK commented on Sep 17, 2026

    @LustHK
    Author

    Wow! The people here are really fast.

  6. anojndr commented on Sep 17, 2026

    @anojndr
    Contributor

    Update — my earlier comment here (PR #4105) was an incomplete fix: it covered only 2 of the 4 gates upstream enforces, which is why the 403 came back within hours.

    Live bisection with genuine opencode/1.18.31 + canonical ses_ held constant found the two missing gates Zen enforces with Bearer public:

    • Tool-signature gate: 0–3 tools → 403; the {bash, glob, grep, read} quartet → 200 on both /chat/completions and /responses. Extras allowed, fake names fail. Plain chat callers send no tools, so every such request 403s.
    • Streaming gate: stream:false → 403 on both endpoints even when everything else is valid.

    New PR #4132 completes the fingerprint: forces stream:true upstream (non-stream clients still get JSON via the existing forced-SSE path) and merges the missing quartet declarations, preserving caller tools verbatim. Verified live post-fix: mimo-v2.5-free, ling-3.0-flash-fin-free, nemotron-3.5/3-ultra-free, big-pickle, muse-spark-1.2/1.3-contributor-free all 200, including with non-stream flag. 65 opencode unit tests pass, baselines byte-equal.

  7. added a commit that references this issue on Sep 17, 2026
    12c0c8e
  8. nonamcabibaranani-design commented on Sep 18, 2026

    @nonamcabibaranani-design

    +1, hitting the exact same via 9router proxy. Hope this gets a fix soon!

  9. nonamcabibaranani-design commented on Sep 18, 2026

    @nonamcabibaranani-design

    +1, hitting the exact same FreeTierError via 9router proxy.

  10. added 7 commits that reference this issue on Sep 19, 2026
    67d1664
    57f39fe
    17714da
    6294dae
    3f31147
    44b7c57
    161ab9d
  11. jauharymanshura9-max commented on Oct 19, 2026

    @jauharymanshura9-max

    Additional finding: IP-reputation gate separate from the fingerprint gate

    We've been running 9router with OpenCode free tier through a de-duplicated WARP IP pool (3 distinct egress addresses) and logging every request. Our data shows there are two separate 403 gates, not one:

    1. Fingerprint gate (what this issue covers): missing read tool, wrong User-Agent, wrong session format → "can only be used from within OpenCode"
    2. IP-reputation gate (new finding): even with correct fingerprint, certain IPs get rejected with "abusive traffic from this IP address"

    Quantitative evidence (1000 requests, ~8 hours):

    • Overall success: 94.8% (948/1000)
    • With 3 distinct WARP IPs: 98.2% (593/604)
    • With single IP (old setup): 73.2% (112/153)
    • All 52 errors were 403 FreeTierError — zero 429 quota errors

    Model-specific sensitivity to IP abuse:

    Model Success Rate
    deepseek-v4.1-flash-free(max) 98.8%
    big-pickle 75.9%
    mimo-v2.6-flash-free 62.5%

    Workaround that worked for us: Route 9router's OpenCode provider through Cloudflare WARP with multiple distinct egress IPs. De-duplicate the pool (WARP assigns from a small regional pool — nodes collide by default). Automatic failover on 403/429 across different IPs.

    Key insight for 9router: The fingerprint fix (this issue) solves gate #1, but gate #2 (IP abuse) still causes failures for users on flagged IP ranges. Even WARP IPs get flagged over time — a pool of 5+ distinct IPs with automatic rotation provides better sustained reliability.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions