anomalyco / anomalyco/opencode
Anthropic overloaded_error becomes UnknownError and is not retried on native event path
@jlongster is already working on this.
Since Jul 28, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
Anthropic overload errors on the native LLM event path lose their structured retry metadata and terminate the turn instead of entering the existing session retry flow.
When Anthropic emits this SSE error:
{"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}
packages/llm/src/protocols/anthropic-messages.ts converts it to a provider-error event. However, the event has neither retryable: true nor an HTTP-equivalent status. Then packages/opencode/src/session/processor.ts handles every provider-error with:
case "provider-error":
throw new Error(value.message)
This discards the event fields (classification, retryable, and provider metadata). MessageV2.fromError() consequently classifies the plain Error as UnknownError, and SessionRetry.retryable() does not retry the message overloaded_error: Overloaded.
The result is a terminal turn with no useful output. Manually sending another prompt normally succeeds because the provider failure is transient.
This is a regression of the behavior discussed in #20384. The earlier fix PR #20373 was closed without merge, and the current native event path still has the same outcome through a newer code path.
Expected behavior
Anthropic overloaded_error should be represented as a retryable API/provider error (HTTP-equivalent 529) and use the existing exponential-backoff retry flow. Structured provider-error fields should survive until error classification.
Actual behavior
The structured provider error becomes a plain Error, then UnknownError, so no retry occurs and the turn stops.
OpenCode versions
- Observed in OpenCode
1.18.3. - Confirmed by source inspection to remain present in
1.18.8(latest release at the time of reporting).
Steps to reproduce
- Use the native Anthropic Messages route with an Anthropic model.
- Receive an Anthropic SSE
errorevent whoseerror.typeisoverloaded_error. - Observe that the turn stops instead of showing retry status and retrying.
This can be made deterministic in a protocol/processor test by feeding the SSE event above into the Anthropic stream parser and then draining the resulting provider-error through SessionProcessor.process().
Suggested fix
- In
anthropic-messages.ts, maperror.type === "overloaded_error"to a provider event withretryable: true(and preserve the raw type in provider metadata). - In
processor.ts, replacethrow new Error(value.message)with a typed provider-stream error that preservesretryable,classification, and metadata. - In
MessageV2.fromError(), convert that typed error toAPIError; map Anthropic overload tostatusCode: 529andisRetryable: true. - Add a regression test asserting that the SSE payload above reaches
SessionRetryas retryable rather thanUnknownError.
Relevant files
packages/llm/src/protocols/anthropic-messages.ts(onError)packages/llm/src/schema/events.ts(ProviderErrorEvent)packages/opencode/src/session/processor.ts(handleEvent("provider-error"))packages/opencode/src/session/message-v2.ts(fromError)packages/opencode/src/session/retry.ts(retryable)
Environment
- Provider: Anthropic
- Example model: Claude Opus
- OS: macOS
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.