Skip to content

fix: prevent sanitizeUserFacingText false-positives on 402 in normal text#12720

Closed
zerone0x wants to merge 1 commit intoopenclaw:mainfrom
zerone0x:fix/sanitize-user-facing-text-402-false-positive
Closed

fix: prevent sanitizeUserFacingText false-positives on 402 in normal text#12720
zerone0x wants to merge 1 commit intoopenclaw:mainfrom
zerone0x:fix/sanitize-user-facing-text-402-false-positive

Conversation

@zerone0x
Copy link
Contributor

@zerone0x zerone0x commented Feb 9, 2026

Summary

Fixes #12711

sanitizeUserFacingText() calls isBillingErrorMessage() on all outbound messaging text. The /\b402\b/ regex matches "402" in any word-boundary context — including $402.55 in cost reports — replacing the entire response with the billing error warning on channel surfaces (Signal, Telegram, etc.).

Root Cause

Two issues combine to create the false positive:

  1. Loose regex: /\b402\b/ matches "402" in $402.55 because $ is not a word character (word boundary at $4)
  2. No prose guard: sanitizeUserFacingText applies error heuristics to all text equally, whether it's a short API error or a multi-paragraph assistant response

Changes

  • Add looksLikeAssistantProse() guard — detects multi-sentence text (3+ sentences), paragraph breaks (\n\n), and markdown formatting. When text looks like prose, skip all heuristic error checks (billing, HTTP, error prefix)
  • Tighten 402 regex — replace bare /\b402\b/ with context-requiring patterns (/(?:HTTP[/ ]\s*|status[: ]\s*|^)402\s+payment\s+required/i and /\berror\b.*\b402\b/i). The existing "payment required" string pattern already catches the real error case
  • Move JSON error check firstisRawApiErrorPayload is structurally identifiable (JSON structure) and should always be caught regardless of text length
  • Apply prose guard to isBillingErrorMessage — the loose keyword branch (billing + upgrade/credits/payment/plan) also skips prose

Test Plan

  • 134 existing pi-embedded-helpers tests pass
  • 8 new tests cover false-positive scenarios:
    • $402.55 in dollar amounts
    • Multi-paragraph error discussion prose
    • Billing topic prose with markdown
    • Multi-sentence text with error-like prefix
  • Verified real billing errors still caught: "HTTP 402 Payment Required", "insufficient credits", "Error: rate limit exceeded"
  • pnpm lint (0 errors), pnpm build, pnpm format all pass

🤖 Generated with Claude Code (issue-hunter-pro)

Greptile Overview

Greptile Summary

This PR reduces false-positive sanitization of normal assistant responses by adding a looksLikeAssistantProse() guard in sanitizeUserFacingText(), tightening the 402 billing regex to require HTTP/error context, and prioritizing structurally-identifiable JSON error payload detection. It also adds test coverage for previously problematic cases like $402.55 in cost reports and multi-paragraph/markdown assistant text.

Main integration point is src/agents/pi-embedded-helpers/errors.ts, which is used by multiple helpers (sanitizeUserFacingText, formatAssistantErrorText, and failover classification) to decide when to rewrite/label outbound text as an error versus leaving it as user-facing content.

Confidence Score: 4/5

  • Mostly safe to merge, but one guard may hide real billing errors in formatted/multi-line error texts.
  • Changes are localized and well-covered by new tests for the reported false positive, and the 402 regex tightening is sensible. The main remaining risk is the new early-return in isBillingErrorMessage() that can suppress legitimate billing detection for errors containing blank lines/markdown wrappers, which can impact user messaging and failover classification.
  • src/agents/pi-embedded-helpers/errors.ts

…nt prose

`sanitizeUserFacingText()` applied error-detection heuristics (including
`isBillingErrorMessage` with `/\b402\b/`) to all outbound text, causing
normal assistant responses containing "402" (e.g. "$402.55 MTD spend") to
be replaced with a billing error warning on messaging channels.

Two-pronged fix:
1. Add `looksLikeAssistantProse()` guard that detects multi-sentence text,
   paragraph breaks, and markdown formatting — structural signals that
   distinguish assistant prose from short API error messages. Skip all
   heuristic error checks when text looks like prose.
2. Tighten the `/\b402\b/` regex in ERROR_PATTERNS.billing to require HTTP
   error context (e.g. "HTTP 402 Payment Required", "error 402") instead
   of matching bare "402" in any word-boundary position.

JSON error payloads (`isRawApiErrorPayload`) are still caught regardless
of text length since they're structurally identifiable.

Fixes openclaw#12711

Co-Authored-By: Claude <[email protected]>
@openclaw-barnacle openclaw-barnacle bot added the agents Agent runtime and tooling label Feb 9, 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.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +583 to +589
// Skip both strict and loose heuristics for text that looks like normal
// assistant prose — real API billing errors are always short, single-line
// messages, not multi-sentence responses.
// Note: pass original `raw` to preserve case for sentence boundary detection.
if (looksLikeAssistantProse(raw)) {
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Billing errors skipped

isBillingErrorMessage() bails out when looksLikeAssistantProse(raw) is true (errors.ts:583-589). Since looksLikeAssistantProse() returns true for any \n\n or markdown constructs, a real provider billing error that includes a blank line or formatted/wrapped text will be missed and won’t get classified as billing (affects formatAssistantErrorText, sanitizeUserFacingText, and classifyFailoverReason). Consider limiting this guard to the loose keyword branch only, or narrowing the prose checks so they don’t exclude structured/HTTP billing errors.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 583:589

Comment:
**Billing errors skipped**

`isBillingErrorMessage()` bails out when `looksLikeAssistantProse(raw)` is true (`errors.ts:583-589`). Since `looksLikeAssistantProse()` returns true for any `\n\n` or markdown constructs, a real provider billing error that includes a blank line or formatted/wrapped text will be missed and won’t get classified as billing (affects `formatAssistantErrorText`, `sanitizeUserFacingText`, and `classifyFailoverReason`). Consider limiting this guard to the *loose keyword* branch only, or narrowing the prose checks so they don’t exclude structured/HTTP billing errors.

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

@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.

@Takhoffman
Copy link
Contributor

Closing as superseded by the merged sanitize/error-context work:

This PR’s intent appears covered by those merged changes and current mainline tests.

@Takhoffman Takhoffman closed this Feb 19, 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]: sanitizeUserFacingText() matches "402" in normal assistant responses, replacing them with billing error warning

2 participants

Comments