anomalyco / anomalyco/opencode

Zen 429 FreeUsageLimitError is masked as "Unexpected server error" (TypeError in SystemPrompt.environment)

Open
#48,988 2 comments 0 reactions 1 assignee View on GitHub

@MrMushrooooom is already working on this.

Since Sep 14, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
Avg merge
7h 2m
Merged PRs (30d)
384

Description

Description

When the OpenCode Zen free tier is rate-limited, the provider returns a clear, well-formed
429 FreeUsageLimitError. OpenCode discards it and reports an internal TypeError instead,
so the user sees only:

Failed to send prompt
Unexpected server error. Check server logs for details.

This is misleading in two ways:

  1. The actionable provider message ("Rate limit exceeded") never reaches the user.
  2. The ref shown in the UI does not exist in the log, so "check server logs" is unactionable.
Environment
  • OpenCode 1.18.30 (Homebrew, macOS 26 "Tahoe", Apple Silicon)
  • Provider: opencode (Zen), free models — e.g. muse-spark-1.3-contributor-free
  • No Zen credential configured (the free tier needs none — opencode auth list reports 0 credentials)
Steps to reproduce
  1. Use any Zen free model (opencode/mimo-v2.5-free, opencode/muse-spark-1.3-contributor-free, …).
  2. Send any prompt.
  3. Observe Unexpected server error immediately, with a ref.

All free models fail identically, which is the first clue that it is the shared free-tier
limiter rather than a model or config problem.

Evidence

1. The provider says exactly what is wrong. Calling the endpoint directly with the same
header the client sends (x-opencode-session):

$ curl -s -w " http=%{http_code}" https://opencode.ai/zen/v1/chat/completions \
    -H 'content-type: application/json' \
    -H 'x-opencode-session: <session-id>' \
    -d '{"model":"mimo-v2.5-free","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'

http=429 {"type":"error","error":{"type":"FreeUsageLimitError",
"message":"Error from provider (Console): Rate limit exceeded. Please try again later."}}

(Without that header the same endpoint returns
400 {"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}},
so the free tier is gated on the client session, not on an API key.)

2. The log records a client-side TypeError, not the provider error. From
~/.local/share/opencode/log/opencode.log:

level=ERROR message=failed ref=err_a184f806
error="TypeError: undefined is not an object (evaluating 'a.name')"
    at resolve (/$bunfs/root/chunk-36bwgd4p.js:2:1659)
    ...
    at SystemPrompt.environment (/$bunfs/root/chunk-y88jw4qv.js:50:13096)
    at SessionPrompt.run ...

The stack points into SystemPrompt.environment. On dev, that function sorts project
references as references.toSorted((a, b) => a.name.localeCompare(b.name))
(packages/opencode/src/session/system.ts), which throws exactly this TypeError if any
entry has an undefined name. Whether that is the precise trigger here, or a second
undefended .name access on the same path, is for you to confirm — but the crash happens
while building the system prompt, before any provider error can be surfaced.

3. The UI ref is not in the log. The TUI reported ref: err_db8fa078; grepping the log
for that string returns 0 matches (the log's own ref for the same failure was
err_a184f806). The two refs are generated at different layers and never reconciled.

Ruled out

The failure is independent of local configuration. It reproduces identically with:

  • an empty config (only $schema)
  • the MCP block removed
  • the plugin removed from config and its cached package removed from ~/.cache/opencode/packages/
  • the skills directory moved aside
  • a fresh state directory (no DB, no sessions)
  • a different free model
  • a clean brew reinstall opencode
Expected
  • Surface the provider's status and message — e.g. 429 FreeUsageLimitError: Rate limit exceeded. Please try again later. — rather than an internal TypeError.
  • Do not collapse provider errors into UnknownError/"Unexpected server error".
  • Make the ref in the UI resolvable in the log (same ref, or print the log path with it).
  • Since the free tier is quota-limited, a clear "free tier rate limit reached, resets at X / add credits" message would prevent a lot of misdiagnosis.
Related issues

Same symptom, no root cause identified: #36826, #29748, #48792, #41944.
Zen free-tier limiting: #43786, #45132, #33318, #33495, #32971.
Error classification: #47685.

Impact

This is a debugging trap: the opaque error sends users hunting for local causes (plugins,
MCP config, credentials) when nothing local is broken. It cost me an hour of bisecting a
config that was never the problem.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.