Raw process/turn-error text can be delivered to a public channel, not just the owner
Summary
deliverErrorResult (container/agent-runner/src/poll-loop.ts) posts the SDK's raw error text verbatim back to whatever channel triggered the current turn — with no check for whether that destination is public. If a container's claude subprocess dies mid-turn while answering a real message in a public Discord/Slack channel (not a task run, not a DM), the community sees the raw internal error text.
Confirmed live
Observed in practice: Error: Claude Code process exited with code 137 (SIGKILL — the SDK's own ProcessTransport.getProcessExitError, confirmed by reading the published @anthropic-ai/claude-agent-sdk package source) posted to an owner DM. The code path that delivered it has no destination check at all, so the only reason it landed in a DM this time is that a DM happened to be the context of that particular turn — the same path would post identically to a public channel if that's what the turn was answering.
Confirmed via source
poll-loop.ts ~line 661:
if (resultBlocks === 0 && event.isError === true && !routing.taskRun) {
await deliverErrorResult(event.text, routing);
...
}routing = extractRouting(messages) (formatter.ts) is derived purely from whichever inbound message started the turn — it carries no public/private distinction. The one existing safeguard is !routing.taskRun: a scheduled task's error goes to its run log instead, never to any channel. A live conversational turn has no equivalent protection.
The host already has what's needed to add one: messaging_groups.is_group is used elsewhere (src/channels/channel-defaults.ts) to distinguish a DM from a group/public channel. That data isn't threaded down to where deliverErrorResult runs, but the distinction the fix needs already exists in the data model.
Ask
Two related but separable things, either src/messaging_groups.is_group is not currently available at delivery time:
- Never deliver raw process/turn-level error text to a non-owner or public destination. For those, substitute a short generic line ("something went wrong, retrying" or similar) instead of the SDK/provider's internal message.
- Full detail (the real error text) still reaches the owner — either because the turn actually was in the owner's DM, or via a separate host-side notice to the owner's own channel when it wasn't.
Related, but distinct
#3576 (rate-limited turns flood the channel with duplicate error notices) shares this same call site and root cause class (unconditional host-side delivery, no policy gate) but is about repetition of a notice already reaching its destination. This issue is about the notice reaching the wrong destination in the first place, even a single time. Worth fixing together since they're adjacent, but independently valid and separately fixable.
Source: nanocoai/nanoclaw