Skip to content

fix(core): recover unclassified oversized rejections through text-only compaction - #55286

Closed
ImBIOS wants to merge 1 commit into
anomalyco:devfrom
ImBIOS:fix/recover-unclassified-oversized-rejection
Closed

ImBIOS wants to merge 1 commit into
anomalyco:devfrom
ImBIOS:fix/recover-unclassified-oversized-rejection

Conversation

@ImBIOS

@ImBIOS ImBIOS commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Related #46564, #53107. Resolves the #54690 repro (default config).

Proxies and gateways often reject huge bodies with a generic 400 instead of a classified size error, while media counts flat toward tokens and dominates bytes, so neither overflow nor payload recovery triggers and the session dead-ends. This treats an unclassified 4xx against a request at or above 4 MiB as a payload rejection: one text-only compaction rebuild before durable output, reusing the existing single-rebuild limit and opt-out. Small requests and non-4xx failures are untouched.

Note: with compaction.auto: false recovery still declines (existing opt-out semantics), so #46564's exact env needs a separate policy call.

Verified: packages/ai (1811 pass) and packages/core (6639 pass) suites, both typechecks, oxlint clean. New scenarios cover recovery, small-request and 5xx boundaries, plus a classifier test locking in that generic 400s stay unclassified.


Added by the opencode bot (AI-generated).

Fixes #53107

Related: #46564, #54690

Public API: adds the isPayloadTooLargeFailure export to @opencode/ai (backwards compatible)

…y compaction

Proxies and gateways often reject huge bodies with a generic 400 instead of a classified size error, while media counts flat toward tokens and dominates bytes. Treat an unclassified 4xx against a request at or above 4 MiB as a payload rejection: one text-only compaction rebuild before durable output, reusing the existing single-rebuild and opt-out guards. Small requests and non-4xx failures behave exactly as before.
@github-actions

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 72 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new recovery works for the case it targets: I copied the PR's runner scenarios onto the base, where the unclassified oversized-rejection recovery fails, and it passes with the PR. With the PR, the core runner/step tests (235), the packages/ai provider-error tests (38) and both typechecks pass.

The main concern is how broad the new check is. On any request of 4 MiB or more, it treats a streamed provider-error event that has no classification as a size rejection, with no check on what the error actually says. I confirmed this with a temporary test: a session with a large image, then a streamed Overloaded error before any output, got compacted instead of failing. Streamed provider errors almost never carry a classification today (overloads, server errors, mid-stream failures), so long, media-heavy sessions would be summarized whenever the provider has a transient problem. On the non-streamed path, every 4xx InvalidRequest without a classification also counts once the body is large: an unknown model, an unsupported parameter, a bad tool schema. Those spend a summary call and then fail again. Details are inline.

The classified payload-too-large half of this change (isPayloadTooLargeFailure, the payload trigger, the text-only start, recoverOverflow(reason), the AGENTS.md line) is almost word for word the same as the still-open #53108. The two will conflict. It would be cleaner to build the size heuristic on top of #53108, or credit it, than to land both separately.

Public API: the only external change is the new isPayloadTooLargeFailure export from @opencode/ai, which is backwards compatible. Config, events and the HTTP API are unchanged.

Fixes #53107
Related: #46564, #54690

* rejection against a huge request is most likely size-caused, so it recovers like a payload
* rejection. Genuine client bugs stay untouched: small requests never qualify.
*/
const isOversizedRejection = (failure: unknown, requestBytes: number) =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the AIError path, the 4 MiB threshold is the only thing separating a size rejection from any other deterministic 4xx. The classifier returns an unclassified InvalidRequestError for every leftover 4xx (404 model not found, unsupported parameter, bad tool schema; see the end of classifyProviderFailure). Once a session holds a few MB of media, all of those trigger a compaction (an extra summary call that replaces the model-visible context) and then fail again. Some narrower signal would help, e.g. only status 400, or a body with no specific code/param, as in the #54690 response.

This branch counts any streamed provider-error with no classification on a request of 4 MiB or more as a size rejection. Unlike the AIError branch above it, it has no 4xx/client-side gate. I checked with a temporary scenario: an image session over 4 MiB that receives LLMEvent.providerError({ message: "Overloaded" }) before output gets compacted and continues. On base, the step fails instead. Streamed errors are mostly overloads and server-side failures, so this would summarize large sessions on transient errors. Could this branch be dropped, or limited to events that actually look like a client-side size rejection?

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 72-hour window.

Feel free to open a new pull request that follows our guidelines.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Oct 17, 2026
@github-actions github-actions Bot closed this Oct 17, 2026
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.

fix(core): recover sessions after HTTP 413 payload rejections

1 participant