fix: suppress raw JSON parse errors from leaking to Discord channels (#59076) [AI-assisted]#59118
Conversation
Greptile SummaryThis PR adds a targeted fix for JSON parse errors from the Anthropic SDK's SSE streaming layer leaking as raw error messages to Discord channels. It introduces
Confidence Score: 5/5Safe to merge — the change is purely additive, scoped to error formatting paths, and all tests pass. No P0 or P1 issues found. The regex is appropriately scoped, the guard is only active inside error-context paths, and five new tests lock in the intended behaviour. All remaining observations are at most P2 style notes. No files require special attention. Reviews (1): Last reviewed commit: "fix: suppress raw JSON parse errors from..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 082dba2343
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Thanks for chasing this leak down. Routing the fix through That said, I do not think the current implementation is robust enough yet.
That is a pretty fragile contract for a user-facing fix, especially since So my concern is not the scope of the fix, but the level it is implemented at: this currently looks more like a patch for the observed strings than a robust fix for the underlying error class. I think the best path would be one of:
As written, I do not think we can confidently say this fixes the general leak class yet. |
|
ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical. Source PR: #59118 |
082dba2 to
d82d524
Compare
|
Codex review: needs maintainer review before merge. What this changes: This PR classifies malformed Anthropic SSE JSON fragments as a stable transport error, renders friendly assistant/TUI/channel-facing text, adds regression tests, and adds a changelog entry. Maintainer follow-up before merge: This is already an open implementation PR with maintainer repair commits; the remaining action is human review, exact-head CI/rebase judgment, and landing rather than a separate automated fix PR. Best possible solution: Land the focused transport-boundary classification and shared rendering fix after maintainer review and exact-head validation, while keeping wider retry/failover work separate from this leak-suppression PR. Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against a972c9ec4547. |
|
This assigned pull request has been automatically marked as stale after being open for 27 days. |
90345ef to
7c4f54f
Compare
cbe6a16 to
c0bd453
Compare
…penclaw#59076) [AI-assisted] When streaming tool calls with long CJK text, the Anthropic SDK's SSE parser can throw SyntaxError (e.g. 'Expected "," or "}" after property value in JSON at position 334'). This error propagates through pi-ai's catch block as an assistant error message and reaches formatAssistantErrorText, which did not recognize the pattern and forwarded the raw error text to the Discord channel. - Add isStreamingJsonParseError() detector in pi-embedded-helpers/errors.ts - Intercept in formatAssistantErrorText() to return a friendly message - Also guard sanitizeUserFacingText() errorContext path for defense-in-depth - Add 5 test cases covering various JSON parse error patterns and contexts Verified: 131 related tests pass, pnpm build succeeds, zero regression. AI-assisted: code fix and test generation verified by automated test runs
…gh TUI/raw formatter paths
c0bd453 to
b8b3686
Compare
|
Merged via squash.
Thanks @singleGanghood! |
…penclaw#59076) [AI-assisted] (openclaw#59118) Merged via squash. Prepared head SHA: b8b3686 Co-authored-by: singleGanghood <156392444+singleGanghood@users.noreply.github.com> Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com> Reviewed-by: @hxy91819
…penclaw#59076) [AI-assisted] (openclaw#59118) Merged via squash. Prepared head SHA: b8b3686 Co-authored-by: singleGanghood <156392444+singleGanghood@users.noreply.github.com> Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com> Reviewed-by: @hxy91819
…penclaw#59076) [AI-assisted] (openclaw#59118) Merged via squash. Prepared head SHA: b8b3686 Co-authored-by: singleGanghood <156392444+singleGanghood@users.noreply.github.com> Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com> Reviewed-by: @hxy91819
When streaming tool calls with long CJK text, the Anthropic SDK's SSE parser can throw SyntaxError. This error was forwarded as-is to the Discord channel instead of being caught and rewritten to a user-friendly message.
Summary
Expected ',' or '}' after property value in JSON at position 334) from the Anthropic SDK streaming layer are leaked to Discord channels as standalone messages.isStreamingJsonParseError()detector inpi-embedded-helpers/errors.tsthat intercepts JSON parse error patterns in bothformatAssistantErrorText()andsanitizeUserFacingText(), replacing them with a friendly "LLM streaming response contained a malformed fragment. Please try again." message.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause / Regression History (if applicable)
formatAssistantErrorText()inpi-embedded-helpers/errors.tshas a comprehensive pattern-matching chain for known error types (context overflow, billing, rate limit, role ordering, transport, etc.), but lacked a pattern for JSON parse errors from streaming SSE data. Unrecognized errors fall through to L949 which returns the raw error text (truncated to 600 chars).SyntaxErrormessages fromJSON.parsefailures in the streaming pipeline.@anthropic-ai/sdk/src/core/streaming.tsL69-75 whereJSON.parse(sse.data)is called on each SSE event. The SDK re-throws the SyntaxError, whichpi-ai'sstreamAnthropiccatch block (L340) captures and converts tooutput.errorMessage. This flows through the agent lifecycle handler toformatAssistantErrorText().parseStreamingJson()function in pi-ai (used forinput_json_deltapartial JSON) is safe (triple-fallback). The problem is in the SDK's SSE layer, which parses the raw SSEdata:line with strictJSON.parsebefore pi-ai ever sees the event.Regression Test Plan (if applicable)
src/agents/pi-embedded-helpers.formatassistanterrortext.test.tsformatAssistantErrorTextreturns a friendly message (not raw error text) when the error matches JSON parse error patterns from streaming SDKs.formatAssistantErrorTextfunction is the last-mile sanitizer before error text reaches channels. Testing at this layer catches all upstream error sources without needing to mock the full streaming pipeline.sanitizeUserFacingTextcontext tests.User-visible / Behavior Changes
Expected ',' or '}' after property value in JSON at position 334 (line 1 column 335)appear as standalone Discord messages."LLM streaming response contained a malformed fragment. Please try again."— a clear, non-technical message that tells the user what happened and what to do.Diagram (if applicable)
Security Impact (required)
No)No)No)No)No)Repro + Verification
Environment
[skills: legal, lawclaw]in topic (adds ~10KB of skill context with regex patterns)Steps
[skills: legal, lawclaw]in the topicEditorWritewith substantial Chinese text contentExpected
Actual
Expected ',' or '}' after property value in JSON at position 334 (line 1 column 335)appear as standalone Discord messages.Evidence
5 new test cases added and passing:
sanitizes streaming JSON parse errors from Anthropic SDK (#59076)— verifiesExpected ',' or '}' ...patternsanitizes 'Expected double-quoted property name' JSON parse errors (#59076)— verifiesExpected double-quoted...patternsanitizes 'Unexpected token' JSON parse errors (#59076)— verifiesUnexpected token...patternsanitizeUserFacingText: rewrites JSON parse error in error context— verifies sanitize pathsanitizeUserFacingText: does not rewrite when not in error context— ensures normal text is not affectedAll 131 related tests pass.
pnpm buildsucceeds. AI-generated code verified by automated test runs.Human Verification (required)
sanitizeUserFacingTextonly rewrites in error context (doesn't affect normal assistant text mentioning JSON), (3) regex pattern doesn't false-positive on unrelated error messages.Review Conversations
Compatibility / Migration
Yes)No)No)Risks and Mitigations
\b(?:expected|unexpected)\b.+\bin json\b.+\bposition\bcould theoretically match an assistant message that happens to contain all three keywords in sequence (e.g., explaining JSON parsing to a user).formatAssistantErrorText()(which processesstopReason: "error"assistant messages) and insidesanitizeUserFacingText()only whenerrorContext: true. Normal assistant text is never routed through these error-handling paths. Additionally, the regex requires all three keywords (expected/unexpected,in JSON,position) in a single line, making false positives on natural language extremely unlikely.