fix(agent): classify jiter SSE parse failures as retryable (#65147) - #65154
Open
wesleysimplicio wants to merge 3 commits into
Open
fix(agent): classify jiter SSE parse failures as retryable (#65147)#65154wesleysimplicio wants to merge 3 commits into
wesleysimplicio wants to merge 3 commits into
Conversation
Contributor
|
Thanks for tracing this to the local-validation gate. The premise remains valid on current main: Problems
Suggested changes
Automated hermes-sweeper review. |
Contributor
Author
|
Both fixed:
Fail-before verified: reverting only the regex to the old bare-suffix version makes the new negative test fail exactly as expected — Broader retry-classifier suite: |
added 3 commits
August 10, 2026 17:19
…rch#65147) jiter (the Rust JSON parser the openai SDK >=1.x uses for streamed SSE chunks) raises a plain ValueError on a truncated/corrupted data: payload - not a json.JSONDecodeError subclass, so the NousResearch#14271/NousResearch#14782 carve-out doesn't catch it. The classifier in conversation_loop.py treated this as a local programming bug and aborted on attempt 1/3 instead of retrying, even though the same transient failure recovers fine seconds later. jiter has no dedicated exception class, so match its consistent message shape ("... at line N column N") instead, and only for a bare ValueError (not a subclass already covered by other carve-outs).
… real loop test Maintainer review (hermes-sweeper) on this PR found two real gaps: 1. _JITER_PARSE_ERROR_RE only checked the trailing 'at line N column N' suffix, which is not jiter-specific -- an unrelated local ValueError coincidentally ending in that suffix would be misclassified as retryable, widening the carve-out beyond jiter's actual failures. Fixed by requiring the message to also start with one of jiter's real, stable error phrases (verified directly against the installed jiter package). 2. The belt-and-suspenders test read production source via inspect.getsource, which AGENTS.md bans. Replaced it with two real tests driving the actual conversation loop through agent.run_conversation() with a mocked client: one where a jiter-shaped ValueError on the first call retries and succeeds on the second, and one where a same-suffix but non-jiter ValueError aborts immediately without retrying. Validation: uv run --extra dev pytest tests/run_agent/test_jsondecodeerror_retryable.py -q -> 15 passed. Fail-before: reverted only the regex to the old bare-suffix version; the new negative real-loop test failed exactly as expected (retried 3 times instead of aborting on attempt 1). ruff check: clean. Broader retry suite (uv run --extra dev pytest tests/run_agent/ -q -k 'retry or retryable or jiter or jsondecode'): 61 passed, no regressions.
wesleysimplicio
force-pushed
the
fix/jiter-parse-error-retryable
branch
from
August 10, 2026 20:19
9f827fe to
2c9a907
Compare
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
A transient provider/network failure (a truncated/corrupted
data:SSEevent) surfaces from jiter — the Rust JSON parser the openai SDK
>=1.xuses to parse streamed chunks — as a plainValueError. Thenon-retryable classifier in
agent/conversation_loop.pyonly carves outjson.JSONDecodeError(added for #14271/#14782), so a jiter parse errorstill gets misclassified as a local programming bug and aborts on
attempt 1/3 instead of retrying — even though an identical request
retried seconds later succeeds.
Changes
agent/conversation_loop.py: added_JITER_PARSE_ERROR_RE(matchesjiter's consistent
"... at line N column N"message shape, since ithas no dedicated exception class) and excluded that shape — only for a
bare
ValueError, not any subclass already covered by other carve-outs— from
is_local_validation_error.tests/run_agent/test_jsondecodeerror_retryable.py: extended theexisting mirror-predicate test file (same pattern as the [Bug]: JSONDecodeError bypasses retry logic due to ValueError inheritance #14782 and
Treat NoneType provider shape errors as retryable #33136 carve-outs) with
TestJiterParseErrorIsRetryable(positive case,a bare unrelated
ValueErrorstill aborts, and aJSONDecodeErrorisn't double-matched) and
TestAgentLoopSourceHasJiterCarveOut(belt-and-suspenders check that the production source actually contains the
carve-out).
Validation
pytest tests/run_agent/test_jsondecodeerror_retryable.py -qconversation_loop.pychange)TestAgentLoopSourceHasJiterCarveOutfails as expected — carve-out absentpytest tests/run_agent/ -q -k "retryable or jsondecode or jiter" --ignore=tests/run_agent/test_strip_reasoning_tags_cli.pyruff check agent/conversation_loop.py tests/run_agent/test_jsondecodeerror_retryable.py(
test_strip_reasoning_tags_cli.pyis excluded — it fails to collect ona clean
maincheckout too, due to a missing localprompt_toolkitdependency unrelated to this change.)
Closes #65147