Skip to content

fix(agents): suppress tool error warnings when assistant already replied#17552

Closed
AytuncYildizli wants to merge 4 commits intoopenclaw:mainfrom
AytuncYildizli:fix/suppress-exec-error-channel-leak
Closed

fix(agents): suppress tool error warnings when assistant already replied#17552
AytuncYildizli wants to merge 4 commits intoopenclaw:mainfrom
AytuncYildizli:fix/suppress-exec-error-channel-leak

Conversation

@AytuncYildizli
Copy link
Copy Markdown
Contributor

@AytuncYildizli AytuncYildizli commented Feb 15, 2026

Summary

Fixes #9651

When the assistant composes a user-facing reply, shouldShowToolErrorWarning now returns false — the error is not surfaced as a separate ⚠️ … failed payload. Previously, the function unconditionally returned true for any tool in MUTATING_TOOL_NAMES, bypassing the hasUserFacingReply check entirely.

Because exec and bash are in MUTATING_TOOL_NAMES, every non-zero exit — including perfectly normal ones like grep returning code 1 (no match) or find with no results — produced a warning message that leaked to messaging channels (Telegram, WhatsApp, Discord) as a separate chat bubble.

Root cause

// Before (payloads.ts — shouldShowToolErrorWarning)
const isMutatingToolError = params.lastToolError.mutatingAction
  ?? isLikelyMutatingToolName(params.lastToolError.toolName);
if (isMutatingToolError) {
  return true;           // ← bypasses hasUserFacingReply entirely
}

isMutatingToolCall unconditionally returns true for exec/bash (tool-mutation.ts:107-108), so buildToolMutationState always sets mutatingAction = true, and the early return fires on every failed command.

Fix

  • payloads.ts: Move the hasUserFacingReply check above the mutating-tool branch. When the assistant already addressed the error in its reply, duplicating it as a separate chat bubble is noise. When no reply exists, mutating-tool errors are still always surfaced as the sole failure signal.
  • handlers.tools.ts: Guard emitToolOutput with !isToolError so error payloads are not emitted as regular tool output on verbose channels — matching the existing guard already used for media delivery (line 279).

What changes

Scenario Before After
exec fails, assistant replies with explanation ⚠️ Exec: … failed leaked as separate message Suppressed — assistant reply is sufficient
write fails, assistant replies "Done." Duplicate error bubble Suppressed — assistant already replied
write fails, no assistant reply Error shown Error shown (unchanged)
message send fails, no assistant reply Error shown Error shown (unchanged)
Non-mutating tool fails, no reply Error shown Error shown (unchanged)
suppressToolErrors enabled, mutating, no reply Error shown Error shown (unchanged)

Local validation

  • pnpm build — clean ✅
  • pnpm check — clean ✅
  • pnpm test — all 5,136 unit tests pass ✅
  • 21 e2e tests pass ✅
  • Tested locally on a production OpenClaw instance (Mac Studio, WhatsApp channel) — the duplicate ⚠️ Exec: … failed bubbles no longer appear when the assistant has already replied with an explanation.

Tests

Scope

Single focused change: fix the duplicate error-message leak on messaging channels. Two files modified (payloads.ts, handlers.tools.ts), both addressing the same root cause from different angles.

AI-assistance transparency

  • AI-assisted: This PR was authored with the help of Claude (Anthropic) via OpenClaw — specifically, the exec tool error was discovered during daily usage of an OpenClaw agent on WhatsApp, and the fix was developed interactively.
  • Testing level: Fully tested — all existing unit tests updated, 3 new targeted tests added, full pnpm build && pnpm check && pnpm test suite passes, and the fix was validated on a live production instance.
  • Understanding: The contributor (@AytuncYildizli) understands the logic change and has been running OpenClaw with this patch in production since Feb 14, 2026 without regressions.

Related

Greptile Summary

Fixes duplicate error messages on messaging channels by prioritizing assistant replies over raw tool errors. Previously, mutating tool errors (like exec or bash non-zero exits) always generated separate warning bubbles even when the assistant already explained the situation - this was especially noisy on WhatsApp/Telegram/Discord where each payload becomes a distinct chat bubble.

Key changes:

  • payloads.ts: Reordered shouldShowToolErrorWarning logic to check hasUserFacingReply before the mutating-tool branch, suppressing duplicate error warnings when assistant has already replied
  • handlers.tools.ts: Added !isToolError guard to emitToolOutput preventing error payloads from being emitted as regular tool output (matches existing guard on line 294 for media delivery)
  • Tests updated to reflect new behavior with 3 new test cases covering the exact scenarios from issue [Bug]: Exec tool error output (non-zero exit code) sent as message to active WhatsApp/Telegram channel #9651

The fix maintains the safety guarantee: mutating tool errors are still surfaced when there's NO assistant reply (the only failure signal).

Confidence Score: 5/5

  • Safe to merge - focused fix with comprehensive test coverage and production validation
  • The logic change is well-reasoned and addresses the root cause correctly. All existing tests pass (5,136 unit + 21 e2e), new tests cover the exact scenarios, and the author has run this in production since Feb 14. The change maintains safety by still showing errors when there's no assistant reply.
  • No files require special attention

Last reviewed commit: 9f7eca5

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S labels Feb 15, 2026
@AytuncYildizli
Copy link
Copy Markdown
Contributor Author

Thanks for the checklist! Updated the PR description to align with CONTRIBUTING.md:

  • Local validation: pnpm build && pnpm check && pnpm test — all 5,136 unit tests + 21 e2e tests pass. Also tested on a live production instance (WhatsApp channel).
  • Focused scope: Single fix — duplicate error messages leaking to messaging channels. Two files changed, both addressing the same root cause.
  • What + Why: Detailed root cause analysis, behavior change table, and related issues in the description.
  • AI-assistance transparency: Authored with Claude via OpenClaw. Fully tested (not just generated). Running in production since Feb 14 without regressions.

Let me know if anything else is needed for review! 🦞

@AytuncYildizli
Copy link
Copy Markdown
Contributor Author

Just resolved the merge conflict with upstream's new suppressToolErrorWarnings parameter — PR is clean against main now.

The two guards are complementary and don't overlap:

  • suppressToolErrorWarnings: config-driven suppression (upstream's new param)
  • hasUserFacingReply: automatic suppression when the assistant already addressed the error in its reply

This is a pretty common pain point for anyone running OpenClaw on messaging channels (WhatsApp, Telegram, Discord) — the duplicate error bubbles are confusing for end users and make the assistant look broken even when it handled the error gracefully.

Happy to address any feedback! 🙏

@steipete steipete closed this Feb 16, 2026
@steipete steipete reopened this Feb 17, 2026
@AytuncYildizli AytuncYildizli force-pushed the fix/suppress-exec-error-channel-leak branch 3 times, most recently from ff9be9a to 3599d86 Compare February 17, 2026 03:32
AytuncYildizli and others added 2 commits February 17, 2026 07:05
When the assistant composes a user-facing reply, tool errors are no
longer surfaced as separate warning payloads.  Previously,
`shouldShowToolErrorWarning` unconditionally returned `true` for
mutating tools (exec, write, bash, …), causing every failed command —
including benign non-zero exits like `grep` returning code 1 — to
produce a `⚠️ … failed` message on messaging channels (Telegram,
WhatsApp, Discord).

The fix moves the `hasUserFacingReply` check above the mutating-tool
branch: when the assistant already addressed the error in its reply,
duplicating it as a separate chat bubble is noise.  When no reply
exists, mutating-tool errors are still always surfaced as the sole
failure signal.

Additionally guards `emitToolOutput` with `!isToolError` so error
payloads are not emitted as regular tool output on verbose channels —
matching the existing guard used for media delivery.

Fixes openclaw#9651

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@AytuncYildizli AytuncYildizli force-pushed the fix/suppress-exec-error-channel-leak branch from 6f4ad96 to fdaa39f Compare February 17, 2026 04:06
@openclaw-barnacle openclaw-barnacle bot added channel: voice-call Channel integration: voice-call gateway Gateway runtime commands Command implementations size: S and removed size: XS labels Feb 17, 2026
@AytuncYildizli
Copy link
Copy Markdown
Contributor Author

Thanks @stijnhoste! Appreciate you linking this, happy to see both approaches converge. 🤝

@steipete
Copy link
Copy Markdown
Contributor

Closing as AI-assisted stale-fix triage.

Linked issue #9651 ("[Bug]: Exec tool error output (non-zero exit code) sent as message to active WhatsApp/Telegram channel") is currently CLOSED and was closed on 2026-02-23T01:47:22Z with state reason COMPLETED.
Given that issue state, this fix PR is no longer needed in the active queue and is being closed as stale.

If the underlying bug is still reproducible on current main, please reopen this PR (or open a new focused fix PR) and reference both #9651 and #17552 for fast re-triage.

@steipete
Copy link
Copy Markdown
Contributor

Closed after AI-assisted stale-fix triage (closed issue duplicate/stale fix).

@steipete steipete closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: voice-call Channel integration: voice-call commands Command implementations gateway Gateway runtime size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Exec tool error output (non-zero exit code) sent as message to active WhatsApp/Telegram channel

2 participants