🤖 tests: fuzz gateway, provider routing, and stream error paths; fix error-serialization bugs - #4021
Merged
Merged
Conversation
…am error paths Deterministic seeded fuzz tests (no new deps) covering: - gateway stream usage/finishReason normalization (hostile upstream payloads) - model string parsing/normalization idempotence + prototype-pollution keys - refusal-fallback chain sanitization (bounded, deduped, acyclic) - error extraction/clamping/429 classification with hostile thrown values - pure route resolution with garbage priorities/overrides - Coder gateway catalog parsing and model-id mapper roundtrips - StreamManager chaos: hostile chunk streams must settle with a terminal event, leak no unhandled rejections, and never wedge the workspace Fixes found by fuzzing: - getErrorMessage could throw despite its non-throwing contract: String(error) on a hostile Proxy/throwing toString escaped the guard (it runs in stream-failure paths where a throw masks the real provider error) - getErrorMessage degraded cyclic/BigInt provider error payloads to "[object Object]" because bare JSON.stringify threw; now serializes with a cycle-safe replacer so the payload's actual fields survive - StreamManager error-part fallback used bare JSON.stringify, replacing cyclic provider errors with a serialization TypeError; now uses getErrorMessage
This comment has been minimized.
This comment has been minimized.
Member
Author
|
@codex review |
Member
Author
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8aab9b9dc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- getErrorMessage: track only the ancestor chain when serializing so shared (non-cyclic) sibling references stay intact; only true cycles become [Circular] - streamManager: route tool-error payload serialization through getErrorMessage so cyclic/BigInt tool errors stay recoverable tool errors - flatUsageToV3: sanitize non-finite token counts (NaN/Infinity) to undefined so they cannot leak into usage/cost arithmetic; fuzz asserts finiteness - gateway model-id mappers: reject leading/trailing separators (slash and dot) so empty origins/model ids cannot form invalid canonical identities; fuzz asserts non-empty parts - chaos test: actually start and settle a second stream on the same workspace to exercise the reuse path
Member
Author
|
@codex review |
Member
Author
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a deterministic fuzzing/chaos pass over the AI Gateway integration, provider routing/resolution, refusal-fallback logic, and stream error handling — and fixes three error-path bugs the campaign surfaced (all in how hostile provider error payloads are stringified/propagated).
Background
A faulty upstream provider recently hung/broke the agent loop until manual intervention, suggesting hidden edge cases in provider failure handling. This PR probes the mux-owned failure surfaces with seeded fuzz tests: gateway payload normalization, model-string parsing, fallback-chain resolution, route resolution, Coder gateway catalog parsing, error classification, and StreamManager's chunk-consumption loop.
Implementation
src/common/utils/testing/fuzzHelpers.ts: dependency-free seeded PRNG (mulberry32) plus hostile value/string generators (prototype-pollution keys, lone surrogates, cyclic objects, BigInt, throwing getters/Proxies). Every fuzz test reports its seed, so failures replay deterministically.*.fuzz.test.ts/ chaos suites asserting totality (never throw), idempotence (normalization survives persist/reload round-trips), boundedness (fallback chains ≤ 3, deduped, acyclic; clamped errors stay clamped), and terminal settlement (every hostile stream ends in a terminal event with zero unhandled rejections and no wedged workspace; 40 seeded iterations againstStreamManagerwith malformed deltas, unknown chunk types, mid-stream throws, truncation, and garbage usage payloads).Fixes found by the campaign:
getErrorMessagecould throw despite its non-throwing contract: theString(error)fallback sat outside the try, so a hostile Proxy / throwingtoStringescaped — in stream-failure paths this masks the real provider error.getErrorMessagedegraded cyclic/BigInt provider payloads to"[object Object]"because bareJSON.stringifythrew; it now serializes with a cycle/BigInt-safe replacer so the payload's actual fields survive to the UI.StreamManager's error-chunk fallback used bareJSON.stringify(errorObj), replacing cyclic provider errors with aConverting circular structure to JSONTypeError; it now routes throughgetErrorMessage(regression test included).Validation
"[object Object]"degradation for circular error objects, which this PR intentionally improves.Risks
Low. Production changes are confined to error-message serialization fallbacks (
errors.ts, oneStreamManagererror-part branch); behavior only changes for error payloads that previously crashed serialization or degraded to"[object Object]". Affected area: error reporting in stream-failure paths. UTF-8/SSE byte-boundary decoding lives inside the AI SDK (not mux-owned), so it is intentionally out of scope; socket-level fault injection against a live gateway would need an integration harness and is noted as follow-up material.Generated with
xum• Model:anthropic:claude-fable-5• Thinking:xhigh• Cost:$13.41