Skip to content

fix: suppress tool error payloads from user-facing delivery#23147

Closed
ahdernasr wants to merge 1 commit intoopenclaw:mainfrom
ahdernasr:fix/suppress-tool-error-leaks
Closed

fix: suppress tool error payloads from user-facing delivery#23147
ahdernasr wants to merge 1 commit intoopenclaw:mainfrom
ahdernasr:fix/suppress-tool-error-leaks

Conversation

@ahdernasr
Copy link
Copy Markdown
Contributor

@ahdernasr ahdernasr commented Feb 22, 2026

Problem

Tool results with isError: true (e.g., file path validation errors, exec failures, rate limit messages) are forwarded to the user's chat channel. This leaks internal details like file paths, stack traces, and infrastructure error messages that users should never see.

Example from production:

⚠️ ✉ Message failed: Local media path is not under an allowed directory: /tmp/assignment_final.docx

This is a systemic issue affecting all tool types and all channels. Multiple issues have been filed:

And multiple partial fixes have been attempted (#17950, #10261, #17552), each targeting specific tool types rather than the root cause.

Fix

Add an isError guard at the top of resolveToolDeliveryPayload() in dispatch-from-config.ts. When a tool result has isError: true, the payload is suppressed from channel delivery entirely.

This is a single-point fix at the dispatch layer that covers:

  • All tool types (exec, message, browser, etc.)
  • All channel types (DM, group, routed)
  • All surfaces (Telegram, Slack, Discord, etc.)

The error payload is still visible to the model (so it can react, retry, or inform the user in its own words) — only the raw channel-side delivery is suppressed.

Changes

  • dispatch-from-config.ts: 8-line guard at the top of resolveToolDeliveryPayload()
  • dispatch-from-config.test.ts: 3 new test cases:
    1. Suppresses error payloads in DM sessions
    2. Suppresses error payloads even when they contain media
    3. Suppresses error payloads in group chats while still forwarding non-error media

Testing

All 18 tests pass (15 existing + 3 new).


Follow-up to #21231 (tool result serialization) — same dispatch area, different bug.

Greptile Summary

Adds a security fix that prevents internal tool error details from leaking to user-facing channels. The fix adds an isError guard at the top of resolveToolDeliveryPayload() in dispatch-from-config.ts:331-333, which suppresses all tool results with isError: true from being delivered to users while still making them visible to the model for retry/recovery logic.

Key changes:

  • Single-point fix at the dispatch layer that covers all tool types, channel types, and surfaces
  • Error payloads are checked after TTS processing but before channel delivery (dispatch-from-config.ts:360)
  • Comprehensive test coverage with 3 new test cases covering DM sessions, media-containing errors, and group chats
  • The fix properly handles both dispatcher and route-reply code paths since the guard runs before either delivery mechanism

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - it's a targeted security fix with comprehensive tests
  • The fix is surgically placed at the right architectural layer (single point before all delivery mechanisms), has excellent test coverage (3 new tests covering different scenarios), and follows the principle of fail-safe defaults. The implementation is simple (8-line guard with clear comment), making it easy to understand and maintain. All 18 tests pass.
  • No files require special attention

Last reviewed commit: 4f6324f

(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

Tool results with isError: true (e.g., file path errors, exec failures,
rate limit messages) were being forwarded to the user's chat channel,
leaking internal details and file paths.

Add an isError guard at the top of resolveToolDeliveryPayload() in the
dispatch layer so error payloads are never delivered to any channel
(DM, group, or routed). The error is still visible to the model for
retry/recovery — only the channel-side delivery is suppressed.

This is a single-point fix that covers all tool types and all channels,
addressing the root cause behind openclaw#17828, openclaw#12928, and openclaw#20279.

Tests: 3 new cases covering DM, group, and media-bearing error payloads.
@steipete
Copy link
Copy Markdown
Contributor

Hmm - as a user I kinda wanna see when something fails tho?

please use codex to review:
• Findings (blocking)

  1. High: this PR does not cover the main leak path. Raw tool error text is still
    built into final payloads in src/agents/pi-embedded-runner/run/payloads.ts:275 and
    sent as normal replies; the new guard only affects onToolResult delivery in src/
    auto-reply/reply/dispatch-from-config.ts:342.
  2. High: in the real embedded-runner path, isError is dropped before dispatch (src/
    auto-reply/reply/agent-runner-execution.ts:399), so the new payload.isError check
    in dispatch won’t fire for most tool-result callbacks.
  3. Medium: suppressing all isError tool-result deliveries can hide important mutation
    failures; current behavior intentionally keeps mutating failures visible (src/
    agents/pi-embedded-runner/run/payloads.test.ts:42).

@steipete
Copy link
Copy Markdown
Contributor

Superseding update: we shipped this directly to main with a source-level fix + docs + follow-up refactor, so this PR is now redundant.

What landed

  1. Behavior change (tool error detail gating)
  • Commit: 835be4392 (fix: gate tool error details behind verbose)
  • Change: tool-failure summaries still show to users, but raw error suffixes are hidden by default and only shown when /verbose on|full.
  • Files:
    • src/agents/pi-embedded-runner/run/payloads.ts
    • src/agents/pi-embedded-runner/run/payloads.test.ts
    • src/agents/pi-embedded-runner/run/payloads.errors.test.ts
  1. Changelog + docs
  • Commit: a5e2bd4ea (docs: document verbose-gated tool error details)
  • Files:
    • CHANGELOG.md (Breaking note)
    • docs/tools/thinking.md
    • docs/tools/slash-commands.md
  1. Refactor follow-up
  • Commit: 4c355a28a (refactor: centralize tool-error visibility policy)
  • Changes:
    • centralized warning policy (showWarning + includeDetails) in payload builder
    • deduped verbose checks
    • table-driven error visibility tests + shared assertion helper
  • Files:
    • src/agents/pi-embedded-runner/run/payloads.ts
    • src/agents/pi-embedded-runner/run/payloads.test-helpers.ts
    • src/agents/pi-embedded-runner/run/payloads.test.ts
    • src/agents/pi-embedded-runner/run/payloads.errors.test.ts

Verification run

  • pnpm test -- src/agents/pi-embedded-runner/run/payloads.test.ts src/agents/pi-embedded-runner/run/payloads.errors.test.ts
  • pnpm check
  • pnpm build (for shipped fix/docs pass)

Given these are already on main, closing this PR to avoid duplicate merge/review churn.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants