Skip to content

fix(claude-code): classify invalid_request instead of a dead-end error - #195

Merged
akemmanuel merged 2 commits into
akemmanuel:t3/claude-code-providerfrom
touch2be:fix/claude-code-invalid-request-error
Nov 12, 2026
Merged

akemmanuel merged 2 commits into
akemmanuel:t3/claude-code-providerfrom
touch2be:fix/claude-code-invalid-request-error

Conversation

@touch2be

Copy link
Copy Markdown
Collaborator

Problem

A Claude Code run can fail with a completely opaque message:

Model provider request failed
detail: Claude Code request failed: invalid_request
code: unknown   retryable: false

invalid_request is one of the Claude Agent SDK's SDKAssistantMessageError
codes (Anthropic HTTP 400). The SDK hands us only the bare code — no detail.
On OpenGUI's side two gaps turned it into a dead end:

  1. assistantErrorMessage had no case for invalid_request (nor
    model_not_found, account_on_hold, verification_required,
    cloud_credential_error), so it fell through to the generic wording.
  2. A ClaudeCodeError carries no numeric status, and normalizeModelError
    had no text rule for a plainly-worded bad request — so it landed in
    unknown / "Model provider request failed", with retryable: false and
    nothing actionable for the user.

Real-world trigger that surfaced this: a long session kept re-sending image
attachments whose files had disappeared from /tmp, so every subsequent turn
got a 400 and the session was permanently wedged behind a meaningless error.

Change

  • protocol.ts — assistantErrorMessage: cover every SDK error code.
    invalid_request now explains the likely causes (request too large, or a
    referenced attachment that can no longer be read) and suggests starting a
    new session / removing missing attachments; model_not_found is worded
    clearly; the account/verification/cloud-credential codes map to auth.
  • transport.ts — normalizeModelError: classify plainly-worded bad
    requests (invalid request / model not found) as invalid_request even
    without a numeric status, so Claude Code's text-only errors reach the right
    bucket. Narrow, additive regex; benefits any provider that words a 400 in
    text.
  • Tests for both the errorMessage text path and the new
    assistantErrorMessage code path.

Testing

vp test packages/harness/src/models/claude-code/protocol.test.ts   # 25 passed
vp test .../transport-contracts.test.ts .../claude-code/runtime.test.ts  # 30 passed

Follow-up (not in this PR)

The deeper robustness gap — the provider boundary should degrade a
no-longer-readable image reference to a placeholder instead of sending a
broken block — is worth a separate change so a vanished /tmp file can't
permanently wedge a session.

touch2be and others added 2 commits November 11, 2026 20:28
The Claude Agent SDK surfaces a model rejection as a bare
SDKAssistantMessageError code (e.g. `invalid_request`, `model_not_found`).
A ClaudeCodeError carries no numeric status, so these fell through
`assistantErrorMessage`'s switch and `normalizeModelError` had no text rule
to catch them — users saw the opaque "Model provider request failed /
unknown" with no hint and no way to act.

- assistantErrorMessage: cover every SDK error code, with actionable text
  for invalid_request (oversized request or a referenced attachment that can
  no longer be read) and model_not_found, plus the account/verification/
  cloud-credential auth codes.
- normalizeModelError: classify plainly-worded bad requests ("invalid
  request" / "model not found") as `invalid_request` even without a numeric
  status, so Claude Code's text-only errors reach the right bucket.
- Tests for both paths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@akemmanuel
akemmanuel merged commit b06fce8 into akemmanuel:t3/claude-code-provider Nov 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants