Skip to content

fix(harness): close a stream_event's open block before finish-step on error - #6675

Merged
pedrofrxncx merged 1 commit into
mainfrom
fix/close-stream-blocks-on-error
Aug 28, 2026
Merged

fix(harness): close a stream_event's open block before finish-step on error#6675
pedrofrxncx merged 1 commit into
mainfrom
fix/close-stream-blocks-on-error

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Follows #6670.

#6670 added token-level streaming and, in a same-PR follow-up fix, closes a stream_event-opened text/reasoning block before the finish-step boundary between assistant messages — because the AI SDK's reducer clears its open parts on finish-step, so an -end emitted after it targets a part the reducer no longer knows and throws, killing the run mid-stream.

That same fix was applied at the multi-step boundary (claude-code.ts, inside the message.type === "assistant" branch) but missed the other place a turn ends: fail(), called when the SDK throws mid-turn (a network drop, a crash). fail() emitted finish-step directly, without first calling translator.closeOpenStreamBlocks(). If the SDK throws while a stream_event block is still open (no content_block_stop arrived), that part never gets its -end chunk — no crash this time, but the message reads as still streaming forever in the UI even though the run has already failed and reported an error.

Fix: extracted the step-boundary's "close what's open, then finish" pattern into a small exported helper (errorFinishChunks) and used it in fail() too.

Regression test: packages/harness-runner/claude-code.test.tserrorFinishChunks with a block left open by stream_event (no content_block_stop) now closes it (text-end) before finish-step/finish; confirmed this fails on the pre-fix code (the export doesn't exist there) and passes after.

Reviewer check: cd packages/harness-runner && bun test claude-code.test.ts

Locally ran: bun run fmt, bunx tsc --noEmit (packages/harness-runner), bun test packages/harness-runner/claude-code.test.ts (40 pass), bunx oxlint on both changed files (0 warnings/errors). Full CI validates the rest.


Summary by cubic

Fixes the harness error path so a message no longer reads as still streaming after a mid-turn crash. Previously, fail() emitted finish-step without closing any stream_event-opened block; now it reuses the same close-then-finish logic as the assistant-message step boundary.

  • Extracts the close-open-blocks-then-finish pattern into an exported errorFinishChunks helper and uses it in fail().
  • Adds a regression test for an open block with no content_block_stop.

Written for commit 1adca81. Summary will update on new commits.

Review in cubic

… error

fail() emitted finish-step without closing whatever stream_event had left
open, unlike the assistant-message step boundary a few lines above, which
closes it first (added earlier in #6670 for the same orphan-end hazard). An
SDK throw mid-block leaves that text/reasoning part without its -end chunk,
so it reads as still streaming forever after the run has already failed.
@pedrofrxncx
pedrofrxncx merged commit f304753 into main Aug 28, 2026
33 checks passed
@pedrofrxncx
pedrofrxncx deleted the fix/close-stream-blocks-on-error branch August 28, 2026 12:06
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.

1 participant