Keep the reason a failed Claude Code run reported - #3
Open
yingzhouquan3-art wants to merge 1 commit into
Open
Conversation
A batch of 29 lessons failed with an identical row in structured_notes:
claude_code_failed | Claude Code could not structure this transcript.
The provider raised that fixed string on any non-zero exit and dropped
both stderr and the CLI's own JSON error, so a quota stop, an expired
login and a genuine crash were indistinguishable in the database. What
the CLI had actually printed was:
You've hit your session limit · resets 1:10pm (America/Chicago)
The failure is now recorded as "Claude Code exited <code>: <reason>",
preferring stderr and falling back to the "result" field the CLI
returns in its JSON envelope.
Parsing that envelope needed a second fix. The CLI interleaves plain
text with its JSON result, e.g.
Client.listTools() called but server does not advertise tools capability
{"structured_output": ...}
json.loads() over the whole stream raises on that first line, so a
*successful* run could be reported as claude_code_invalid_output. Both
paths now scan line by line for the first JSON object.
The same batch also lost lessons to DashScope, which answers 400/403
with "not eligible" or "account in good standing" while a free-quota or
newly enabled model propagates. Those are transient, so they now join
429/5xx as retryable, and the Alibaba provider retries six times rather
than three.
Tested on Windows 11 against the 59-lesson course that surfaced this.
The suite has pre-existing platform failures there (5 failures, 54
errors on an unpatched checkout, mostly tempdir teardown holding
pipeline.sqlite3); this branch adds two tests and no new failures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
A third batch of fixes from archiving a 59-lesson course on Windows 11.
Independent of #1 and #2.
1. Every Claude Code failure looked the same in the database
29 lessons failed in one run, each recorded as:
ClaudeCodeStructurer.structureraised that fixed string on any non-zeroexit and discarded both
stderrand the JSON error the CLI prints, so aquota stop, an expired login and a real crash were indistinguishable. It
took patching the provider locally to find out what had actually happened:
Failures now read
Claude Code exited <code>: <reason>, preferringstderrand falling back to theresultfield of the CLI's JSON envelope.2. A successful run could be reported as invalid JSON
The CLI interleaves plain-text diagnostics with its JSON result:
json.loads(process.stdout)raises on the first line, sostructure()reported
claude_code_invalid_outputfor a run that had in factsucceeded. Both the success and failure paths now scan line by line for
the first JSON object instead of parsing the whole stream.
This one is latent rather than reproducible on demand — the diagnostic
line does not appear on every invocation — but when it does, the lesson
is lost and the recorded reason points at the wrong thing.
3. DashScope transients aborted the lesson
Around a free-quota or newly enabled model propagating, DashScope answers
400/403 with
not eligibleoraccount in good standing. These clear ontheir own, so they now join 429/5xx as retryable, and the Alibaba provider
retries six times rather than three.
Testing
Two tests added to
tests/test_structure_service.py, covering thepreserved reason and the interleaved-diagnostics case.
Windows has pre-existing platform failures in the suite — an unpatched
checkout of
maingives 5 failures and 54 errors, mostlytearDownfailing to remove a tempdir while
pipeline.sqlite3is still open. Thisbranch adds two tests and no new failures, verified by diffing the failing
test names against that baseline.
🤖 Generated with Claude Code