Skip to content

Image-count 400s (Azure: "Exceeded maximum number of images (50)") are not classified as context overflow, so media-strip compaction never triggers #39677

Description

@ozanyurtsever

Summary

Azure OpenAI hard-caps requests at 50 images. In long agentic sessions where the model reads many images (screenshots, render stills), the full-history resend eventually crosses that cap and every subsequent turn fails with a fatal 400. opencode already ships an auto-recovery designed for exactly this situation — compact, strip media from context, retry — but it never triggers here, because the error is not classified as context_overflow.

Environment

  • opencode 1.18.5
  • model openai/gpt-5.6-terra via OpenRouter, routed to the Azure upstream

What happens

A session accumulated 47 image read tool results; the next user turn attached 4 more images and failed with:

{"error":{"message":"Provider returned error","code":400,"metadata":{"raw":"{\n  \"error\": {\n    \"message\": \"Exceeded maximum number of images (50) allowed in the request.\",\n    \"type\": \"invalid_request_error\",\n    \"param\": \"input\",\n    \"code\": null\n  }\n}","provider_name":"Azure","is_byok":false}}}

The turn surfaces as a plain non-retryable api_error. Because the oversized history is resent on every turn, the session is permanently poisoned from this point — no retry can succeed, only compaction/media-stripping could.

Root cause

parseAPICallError (packages/opencode/src/provider/error.ts) classifies an error as context_overflow only when one of these holds:

  • isContextOverflow(message) matches (packages/llm/src/provider-error.ts) — the pattern list is entirely token/length phrases (prompt is too long, context_length_exceeded, too many tokens, …),
  • HTTP status is 413,
  • body.error.code === "context_length_exceeded".

Azure's image-count error matches none of them: it is a 400 (not 413), the inner code is null (and OpenRouter's wrapper reports numeric code: 400), and no pattern mentions images.

When classification does return context_overflow, SessionCompaction runs with overflow: true, which compacts, strips media from context, and auto-continues with "The previous request exceeded the provider's size limit due to large media attachments…" (packages/opencode/src/session/compaction.ts) — exactly the right remedy for this failure.

Suggested fix

Add an image-count pattern to patterns in packages/llm/src/provider-error.ts:

/maximum number of images/i,

message() appends the raw response body, so the pattern matches even through OpenRouter's double-wrapped payload (the Azure message is nested as an escaped string inside metadata.raw). Other providers have similar per-request media-count caps; the Azure 50-image message is the one observed in the wild.

Repro sketch

  1. Run a session on an Azure-served OpenAI model (directly, or via OpenRouter with provider.order: ["azure"]).
  2. Have the agent read 50+ images across turns (or attach them as file parts).
  3. The next turn fails with the fatal 400 above instead of compacting with media-strip and continuing.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions