fix: break SDK iterator after result message to prevent hang in pull_request runs by scobbe · Pull Request #1339 · anthropics/claude-code-action (original) (raw)
In some workflow contexts — reliably reproducible for us on pull_request-triggered runs of this action — the Claude Agent SDK query() async iterator does not close after the terminal result message is emitted. The for-await loop in runClaudeWithSdk blocks indefinitely after Claude has finished its work, until the workflow's timeout-minutes cap kills the job.
Symptoms observed in production (4× in our scan-reviewer workflow):
- Claude completes successfully: SDK emits { type: "result", subtype: "success", ... } with the cost / turns / duration set.
- The action then sits with zero log output for the rest of timeout-minutes (we measured 18-19 min of dead time after result).
- The job is cancelled at timeout. writeExecutionFile is never called → no claude-execution-output.json → cost-tracker and other post-steps see nothing.
- Run shows as cancelled, even though Claude did its work and any verdict it posted via gh tools already landed.
Author-mode (workflow_dispatch) runs from the same codebase terminate cleanly the same day, so the hang is specific to certain event triggers.
By SDK contract the result message is terminal — no further messages follow. Break out of the loop immediately after capturing it, regardless of whether the upstream iterator ever closes. If the SDK is later fixed to close cleanly in all contexts, this break becomes a no-op.