Skip to content

fix: guard keyword-based rewrites in sanitizeUserFacingText against false positives#10760

Closed
Drickon wants to merge 1 commit intoopenclaw:mainfrom
Drickon:fix/sanitize-false-positives
Closed

fix: guard keyword-based rewrites in sanitizeUserFacingText against false positives#10760
Drickon wants to merge 1 commit intoopenclaw:mainfrom
Drickon:fix/sanitize-false-positives

Conversation

@Drickon
Copy link
Contributor

@Drickon Drickon commented Feb 6, 2026

Problem

sanitizeUserFacingText() applies keyword-based rewrites to ALL outgoing reply text. When an assistant reply legitimately discusses error-related topics (e.g., "context overflow", "roles must alternate", billing), the entire message gets replaced with a terse error string.

Fixes #3594.

Root Cause

Keyword checks like isBillingErrorMessage() and the role-ordering regex run on every assistant message with no structural guard. Normal conversation that mentions these topics gets incorrectly rewritten.

Fix

Added a looksLikeErrorText() guard that wraps the keyword-based rewrites. It checks for structural signals before allowing keyword matching:

  • Starts with a known error prefix (ERROR_PREFIX_RE)
  • Is a raw JSON API error payload
  • Is an HTTP status line error
  • Starts with a context overflow header pattern

Normal conversational text passes through unchanged. Actual error payloads still get the friendly rewrites.

This builds on the shouldRewriteContextOverflowText() pattern from ea423bb which already guards context overflow detection with similar structural checks.

Changes

  • src/agents/pi-embedded-helpers/errors.ts — Added looksLikeErrorText() guard, wrapped role-ordering and billing keyword checks inside it
  • src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts — Added tests for false positive prevention

Testing

  • All 12 existing sanitize tests pass
  • New tests verify that conversational text mentioning error topics passes through unchanged
  • Actual error payloads (JSON, HTTP status lines, error-prefixed messages) still get rewritten correctly

@openclaw-barnacle openclaw-barnacle bot added app: web-ui App: web-ui agents Agent runtime and tooling labels Feb 6, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +376 to +378
// Skip audio files from being included as <file> blocks.
// OGG/Opus binary data passes looksLikeUtf8Text() and gets misdetected as
// text/tab-separated-values, bypassing the kind==="audio" check above.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extension parsing can break
nameHint.substring(nameHint.lastIndexOf(".")) will return the full string when there is no . (because lastIndexOf returns -1), and it will treat paths like .bashrc as an “extension” of .bashrc. That makes the audio-skip check incorrect for dotless filenames/URLs and can skip/allow attachments incorrectly.

Consider guarding the index (e.g. only compute an extension when lastIndexOf(".") > -1 and/or after the last /).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/media-understanding/apply.ts
Line: 376:378

Comment:
**Extension parsing can break**
`nameHint.substring(nameHint.lastIndexOf("."))` will return the full string when there is no `.` (because `lastIndexOf` returns `-1`), and it will treat paths like `.bashrc` as an “extension” of `.bashrc`. That makes the audio-skip check incorrect for dotless filenames/URLs and can skip/allow attachments incorrectly.

Consider guarding the index (e.g. only compute an extension when `lastIndexOf(".") > -1` and/or after the last `/`).

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, but this comment appears to reference code in src/media-understanding/apply.ts which isn't part of this PR. This PR only modifies src/agents/pi-embedded-helpers/errors.ts — it removes keyword-based error message rewrites that were causing false positives on legitimate assistant replies. No audio/extension logic was changed here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right — I apologize for the confusion. Looking at the PR description and the changes, this PR modifies src/agents/pi-embedded-helpers/errors.ts to fix false positives in sanitizeUserFacingText(), not the media understanding code.

It appears my comment was generated based on outdated or incorrect context about what files were changed in this PR. The audio extension parsing issue I mentioned is not relevant to your changes here.

Your fix — removing keyword-based rewrites from sanitizeUserFacingText() and keeping only structural error detection — looks correct for addressing the false positive issue described in #3594 and #8847.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Additional Comments (1)

ui/src/ui/controllers/chat.ts
Chat history truncation
This drops chat.history limit from 200 to 30. If the UI expects more messages for scrollback/context (e.g. restoring longer sessions, searching, or showing earlier tool results), this will deterministically truncate history after 30 and can break UX/features.

If the intent is performance, consider making this configurable/paginated rather than hard-coding 30, or ensure all callers/UX are updated to match the new limit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/controllers/chat.ts
Line: 36:43

Comment:
**Chat history truncation**
This drops `chat.history` `limit` from 200 to 30. If the UI expects more messages for scrollback/context (e.g. restoring longer sessions, searching, or showing earlier tool results), this will deterministically truncate history after 30 and can break UX/features.

If the intent is performance, consider making this configurable/paginated rather than hard-coding 30, or ensure all callers/UX are updated to match the new limit.

How can I resolve this? If you propose a fix, please make it concise.

@Drickon Drickon force-pushed the fix/sanitize-false-positives branch from a3ededc to c0efc98 Compare February 6, 2026 23:50
@openclaw-barnacle openclaw-barnacle bot removed the app: web-ui App: web-ui label Feb 6, 2026
@Drickon
Copy link
Contributor Author

Drickon commented Feb 8, 2026

Re: the chat history truncation comment — ui/src/ui/controllers/chat.ts is not modified in this PR. This PR only touches src/agents/pi-embedded-helpers/errors.ts to remove keyword-based error rewrites from sanitizeUserFacingText(). The 200→30 limit change you're referencing must be from a different PR or branch.

…alse positives

sanitizeUserFacingText applies keyword-based rewrites (role ordering,
billing, etc.) to ALL outgoing text, including normal assistant replies.
This causes false positives when the assistant legitimately discusses
these topics (openclaw#3594).

Add a looksLikeErrorText() guard that checks structural signals (error
prefix, raw API payload, HTTP status code, context overflow header)
before applying keyword rewrites. Normal conversational text passes
through unchanged.

Builds on the shouldRewriteContextOverflowText() pattern from ea423bb
which already guards context overflow detection.
@Drickon Drickon force-pushed the fix/sanitize-false-positives branch from c0efc98 to 269e758 Compare February 8, 2026 11:27
@Drickon Drickon changed the title fix: sanitizeUserFacingText false positives on keyword matching fix: guard keyword-based rewrites in sanitizeUserFacingText against false positives Feb 8, 2026
@Takhoffman Takhoffman self-assigned this Feb 10, 2026
@Takhoffman
Copy link
Contributor

Fixed in #12988.

This will go out in the next OpenClaw release.

If you still see this after updating to the first release that includes #12988, please open a new issue with:

  • your OpenClaw version
  • channel (Telegram/Slack/etc)
  • the exact prompt/response that got rewritten
  • whether Web UI showed the full text vs the channel being rewritten
  • relevant logs around send/normalize (if available)

Link back here for context.

@Drickon
Copy link
Contributor Author

Drickon commented Feb 10, 2026

Closing in favor of #12988, which handles this more cleanly by scoping rewrites to errorContext rather than removing the keyword checks entirely. That preserves the safety net for actual errors while fixing the false positive path.

Thanks @Takhoffman for the thorough fix.

@Drickon Drickon closed this Feb 10, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: User messages containing error-pattern phrases get rewritten to error text

2 participants