#13467: fix(errors): prevent billing false positive in sanitizeUserFacingText
agents
stale
size: S
trusted-contributor
Cluster:
Error Handling Improvements
## Summary
Fixes #13434
## Problem
`sanitizeUserFacingText()` unconditionally applies `isBillingErrorMessage()` to all user-facing text. The `isBillingErrorMessage` function uses a broad heuristic that matches any text containing both "billing" and one of "payment", "upgrade", "credits", or "plan". This causes assistant-generated content discussing billing/payment topics (e.g., gym membership billing details) to be replaced with the generic billing error warning.
## Fix
Add a `shouldRewriteBillingText()` guard function (matching the existing `shouldRewriteContextOverflowText()` pattern) that distinguishes real billing errors from assistant prose:
1. **Precise billing patterns** (`402`, `insufficient credits`, `credit balance`, `payment required`, `plans & billing`) are rewritten unconditionally — these are unambiguous error strings.
2. **Broad heuristic matches** (`billing + payment/upgrade/credits/plan`) are only rewritten when the text looks like a raw error message (API payload, HTTP error, error prefix, or single-sentence without markdown/paragraphs).
## Reproduction & Verification
### Unit-level (direct function call):
**Before fix (main branch) — Bug reproduced:**
```
--- Assistant content (should NOT be rewritten) ---
"**Billing:** Processed through ABC Financial Services..." ❌ FALSE POSITIVE
"The gym membership billing cycle runs monthly..." ❌ FALSE POSITIVE
"Here is a summary of the billing and payment options..." ❌ FALSE POSITIVE
```
**After fix — All verified:**
```
--- Assistant content (should NOT be rewritten) ---
✅ PASS (all assistant content samples preserved)
--- Real billing errors (SHOULD be rewritten) ---
✅ PASS: "insufficient credits"
✅ PASS: "billing: please upgrade your plan"
✅ PASS: "Your credit balance is too low"
```
### Integration-level (real gateway reply pipeline):
Added `normalizeReplyPayload` integration tests in `src/auto-reply/reply/normalize-reply.test.ts` that exercise the full reply normalization pipeline (`normalizeReplyPayload` → `sanitizeUserFacingText`):
**Before fix (main branch) — Bug reproduced through real pipeline:**
```
normalizeReplyPayload({ text: "**Billing:** ... payments ..." })
→ text: "⚠️ API provider returned a billing error..." ❌ FALSE POSITIVE
```
**After fix — Pipeline preserves assistant content:**
```
normalizeReplyPayload({ text: "**Billing:** ... payments ..." })
→ text: "**Billing:** Processed through ABC Financial Services..." ✅ PRESERVED
normalizeReplyPayload({ text: "insufficient credits" })
→ text: "⚠️ API provider returned a billing error..." ✅ REWRITTEN
```
## Effect on User Experience
**Before fix:**
Sub-agent researches gym membership details → output contains "Billing: ... payments" → parent receives "⚠️ API provider returned a billing error" instead of actual findings.
**After fix:**
Assistant content discussing billing/payment topics is delivered as-is. Real billing errors (402, insufficient credits, etc.) are still correctly caught and rewritten.
## Testing
- ✅ 14 unit tests pass (12 existing + 2 new regression tests in `sanitizeuserfacingtext.test.ts`)
- ✅ 2 new integration tests pass (`normalizeReplyPayload` pipeline in `normalize-reply.test.ts`)
- ✅ `isBillingErrorMessage()` unchanged — error classification for failover/logging still works
Most Similar PRs
#12273: fix: prevent billing error false positive on bare '402' in chat con...
by Yida-Dev · 2026-02-09
78.8%
#19271: fix: remove false-positive billing text rewrite in sanitizeUserFaci...
by MisterGuy420 · 2026-02-17
78.0%
#15109: fix: distinguish transient API errors from billing errors
by jwchmodx · 2026-02-13
76.8%
#9173: Fix: Improve error messaging for API rate limits and billing errors
by vishaltandale00 · 2026-02-04
70.9%
#16307: fix: surface billing/auth FailoverErrors as user-friendly messages
by petter-b · 2026-02-14
67.8%
#8661: fix: display rate limit errors correctly instead of as context over...
by dbottme · 2026-02-04
67.8%
#14290: feat: x402 payment info parsing and configurable billing recovery [AI]
by stubbi · 2026-02-11
67.5%
#23520: fix: trigger failover on Anthropic insufficient_quota (HTTP 400) (#...
by dissaozw · 2026-02-22
65.6%
#13318: fix(agents): prevent sanitizeUserFacingText from rewriting conversa...
by hleliofficiel · 2026-02-10
65.3%
#20251: fix: sanitize error messages to prevent internal details and PII fr...
by aldoeliacim · 2026-02-18
65.2%