diff --git a/src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts b/src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts index 5346f1a830b..0b4a1c14641 100644 --- a/src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts +++ b/src/agents/pi-embedded-helpers.formatassistanterrortext.test.ts @@ -147,6 +147,14 @@ describe("formatAssistantErrorText", () => { ); }); + it("strips leading HTTP status code prefix from non-JSON rate limit messages", () => { + const msg = makeAssistantError("429 Your quota has been exhausted, try again in 24 hours"); + const result = formatAssistantErrorText(msg); + expect(result).toContain("try again in 24 hours"); + expect(result).not.toMatch(/^⚠️ 429\b/); + expect(result).toBe("⚠️ Your quota has been exhausted, try again in 24 hours"); + }); + it("returns a friendly message for empty stream chunk errors", () => { const msg = makeAssistantError("request ended without sending any chunks"); expect(formatAssistantErrorText(msg)).toBe("LLM request timed out."); diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index b7df985e379..0132fa33998 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -68,7 +68,9 @@ const RATE_LIMIT_SPECIFIC_HINT_RE = function extractProviderRateLimitMessage(raw: string): string | undefined { // Try to pull a human-readable message out of a JSON error payload first. const info = parseApiErrorInfo(raw); - const candidate = info?.message ?? raw; + // When the raw string is not a JSON payload, strip any leading HTTP status + // code (e.g. "429 ") so the surfaced message stays clean. + const candidate = info?.message ?? (extractLeadingHttpStatus(raw.trim())?.rest || raw); if (!candidate || !RATE_LIMIT_SPECIFIC_HINT_RE.test(candidate)) { return undefined;