Repository navigation
Conversation
The free-tier gate on opencode.ai validates the User-Agent and the session-id format. The pinned "opencode/1.18.31" no longer matches what the official CLI sends; current builds send the channel form "opencode/latest/<version>/<name>", and traffic with the stale UA is classified as an unidentified client and rejected with 403 FreeTierError / 429 FreeUsageLimitError (decolua#4837, decolua#4861). - send opencode/latest/2.0.29/cli as the default User-Agent (executors opencode/opencode-zen, registry entries, connection test utils) - default x-opencode-client: desktop → cli - hasValidOpencodeVersion accepts both legacy opencode/<semver> and the channel form opencode/<channel>/<semver>/<name>, so a downstream client's valid UA is forwarded instead of silently replaced Session/request id generation already matches the upstream Identifier.create (descending, 6-byte time component) — verified against packages/schema/src/identifier.ts, unchanged. Co-Authored-By: Claude Code <noreply@anthropic.com>
andyvandaric
added a commit
to andyvandaric/9router
that referenced
this pull request
Oct 17, 2026
… strategy in full Problem: the fork ran an older fingerprint contract than upstream frontier on the keyed lane and lacked both proxy escape hatches from issue decolua#4983. opencode-zen still sent the v1 UA plus a stub bash/glob/grep/read quartet with empty schemas and the v1-only x-opencode-request header, the fingerprint helper could not satisfy the gate when a caller tool reuses read/shell with platform-specific wording, and proxyAwareFetch had no way out of an egress the gate had flagged. Changes: port upstream PR decolua#4972 (in-place fingerprint normalization with alias fallback), decolua#4883 (UA opencode/latest/2.0.29/cli across both executors, registry and dashboard test; strict v2 channel matcher kept), decolua#4860 fingerprint/strategy for opencode-zen (verbatim read/shell via applyFingerprintTools, cli client, four session mirrors, drop x-opencode-request and x-api-key for free tier; /zen/v1 to /inference/v1 switch NOT taken), decolua#4987 (open-sse/utils/proxyDispatcher.js with opt-in socks5 dns=local, shared by proxyFetch and the dashboard proxy test, fail-closed ERR_PROXY_DNS_MODE) and decolua#4988 (replay a proxied 403 FreeTierError once on the direct egress, strictProxy contract preserved). undici ^7.19.2 to ^7.30.1. Version 0.5.108. Verification: full suite re-derived on this machine from a git stash -u baseline - failure sets byte-identical (95 = 95, 0 new), passes 3592 to 3617. Targeted opencode/proxy/session groups 214 pass. undici 7.30.1 exposes Socks5ProxyAgent and createSocks5Connection; the local-DNS dispatcher is exercised end to end against a local SOCKS5 plus TLS fixture (11 cases). Root cause of the free-tier 403 is egress-IP load-shedding (decolua#4983), so these ports restore request truth and add escape hatches but cannot make a flagged egress succeed.
luqman-v1
approved these changes
Oct 23, 2026
luqman-v1
left a comment
There was a problem hiding this comment.
LGTM: updates OpenCode user-agent fingerprint to official 2.0 channel form while preserving backward-compatible version checks. Safe and clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4837, #4861
Problem
The free-tier gate on opencode.ai classifies requests by client fingerprint. The pinned
User-Agent: opencode/1.18.31no longer matches the official CLI — current builds send the channel formopencode/latest/<version>/<name>. Traffic with the stale UA is treated as an unidentified client and rejected with403 FreeTierError/429 FreeUsageLimitErroron every free model (issue reports from 2026-10-13/14).Additionally,
hasValidOpencodeVersiononly matched the legacyopencode/<semver>form, so when a downstream client already sent the correct channel-form UA, the executor silently replaced it with the stale pinned one.Fix
User-Agent→opencode/latest/2.0.29/cliin the opencode and opencode-zen executors, both registry entries, and the connection-test utils (5 places).x-opencode-client→cli(matches the official CLI attribution).hasValidOpencodeVersionaccepts both the legacyopencode/1.x.yform and the channel formopencode/<channel>/<semver>/<name>, so a valid downstream UA is forwarded as-is.Not changed
Session/request id generation — verified against the upstream source (
packages/schema/src/identifier.ts,Identifier.createdescending, 6-byte time component + 14 base62 chars). 9router's implementation already matches, so it is left alone.Test
tests/unit/opencode-session.test.js— 25/25 passing, including new expectations for the channel-form UA and the forwarded downstream UA.Known limitation (out of scope)
Since 2026-10-10 the gate also inspects the request body (stream:true, ≥2 tools including one named bash) on the /responses lane. That is an upstream payload restriction, not a header issue — spoofing a bash tool entry is a policy question better discussed separately.
Security note
Only outgoing headers to opencode.ai change. No inbound auth, X-Forwarded-For, or SSRF surface touched.
🤖 Generated with Claude Code