fix: handle errors in streaming output callback to prevent group hangs#719
Closed
cmraible-bot wants to merge 1 commit intoqwibitai:mainfrom
Closed
fix: handle errors in streaming output callback to prevent group hangs#719cmraible-bot wants to merge 1 commit intoqwibitai:mainfrom
cmraible-bot wants to merge 1 commit intoqwibitai:mainfrom
Conversation
The outputChain in container-runner.ts had no .catch() handler, so if the onOutput callback threw (e.g. channel.sendMessage fails), the promise chain would reject silently. Subsequent outputChain.then() calls at the close handler would never fire, causing runContainerAgent's promise to hang forever — permanently blocking all message processing for that group until restart. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Collaborator
|
This looks solid — preventing group hangs from streaming errors is important. @gavrielc mind giving this a quick look? Should be a straightforward review. |
klapom
added a commit
to klapom/nanoclaw
that referenced
this pull request
Mar 5, 2026
…res) Bug fixes applied: - qwibitai#636: task-scheduler recalculates next_run before enqueue - qwibitai#655: LIMIT 200 on message queries to prevent OOM - qwibitai#670: rateLimitResetAt field in ContainerOutput interface - qwibitai#694: ANTHROPIC_MODEL passthrough to container env - qwibitai#700: session rotation at 5MB JSONL threshold - qwibitai#701: session retry on corrupted resume (clear + retry) - qwibitai#708: update_task MCP tool in ipc-mcp-stdio - qwibitai#719: outputChain .catch() to prevent group hang - qwibitai#729: fix send_message description (remove incorrect scheduled-task note) - qwibitai#735: datePrefix() injects current date/time into all agent prompts - qwibitai#738: ANTHROPIC_MODEL from .env passed to agent container - qwibitai#746: systemd OnFailure restart prevention logic (container hardening) - qwibitai#751: DM-with-bot JID normalization - qwibitai#754: setOnPipeCallback to reset idle timer on piped messages - qwibitai#756: cursorBeforePipe rollback on container crash Features added: - qwibitai#723: streaming infrastructure (STREAM_TEXT markers, onStreamDelta) - qwibitai#742: container hardening (entrypoint.sh privilege drop, env sanitize) - qwibitai#680: add-cli skill (CLI send binary) - qwibitai#727: add-memory skill extracted to .claude/skills/add-memory/ - qwibitai#744: add-s3-storage skill extracted to .claude/skills/add-s3-storage/ Test fixes: - Mock fs.promises in container-runner.test.ts to prevent real I/O - Add ANTHROPIC_MODEL to config mock - Fix cpSync expectation: { recursive: true, force: true } - Fix isActive() to use state.active instead of state.process - Fix container-runtime error message: Docker → Container runtime Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
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
• The
outputChainincontainer-runner.tschainsonOutputcallbacks via.then()with no.catch()handler• If
onOutputthrows (e.g.channel.sendMessagefails due to network error, invalid JID, rate limiting), the promise chain silently rejects• The
closehandler usesoutputChain.then(() => resolve(...))— with a rejected chain, this.then()never fires, andrunContainerAgent's promise hangs forever• This permanently blocks all message processing for the affected group until the process is restarted
• Fix: Added
.catch()to the output chain so errors are logged and the chain continues, ensuring the container-runner promise always settlesWhy this matters
The synchronous
try/catcharound line 365 only catchesJSON.parse()errors.onOutputis async (returns a Promise), so when it's scheduled via.then(), any errors it throws happen on a later microtask — outside the synchronoustry/catch. Without.catch()on the promise chain, the rejection is unhandled and the close handler'soutputChain.then(() => resolve(...))never fires.Test plan
onOutput error does not hang the promise— verifies that whenonOutputthrows, the promise still resolves instead of hanging🤖 Generated with Claude Code