Skip to content

Treat bare Anthropic 403 as transient, not a credential failure - #5041

Open
builder-io-integration[bot] wants to merge 2 commits into
mainfrom
ai_main_1a033f8ba1354246a7ad
Open

builder-io-integration[bot] wants to merge 2 commits into
mainfrom
ai_main_1a033f8ba1354246a7ad

Conversation

@builder-io-integration

@builder-io-integration builder-io-integration Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the Anthropic engine so a reasonless (empty-body) 403 response is classified as transient provider load-shedding and retried, instead of ending the turn and telling the user to reconnect a working provider credential.

Problem

Factory item 58ff04c94d0fe98b4ead1bbc7925a3d3425a71e5ae5cb6a79aff792ba4750ca5 (source Slack thread: https://slack.com/app_redirect?team=T0GCV21GE&channel=C0ATH3CCZT4&message_ts=1789455253.090849) reported that generating an interactive wireframe in the Plan app hung on "Working" for ~90 seconds, then crashed with a bare toast: "The agent hit an error — 403 status code (no body)" (code: http_403), aborting the whole generation with no partial output and no actionable message.

Root cause: the Anthropic engine tagged every HTTP status as errorCode: http_<status> regardless of context. A 403 status code (no body) from Anthropic is the provider shedding load under sustained/long-running generation, not a rejected API key — but the engine routed it onto the credential-rejection lane, ending the run on the first occurrence and discarding partial output. The Builder gateway engine and the AI SDK lane had already been fixed for this exact scenario, but the Anthropic engine (used by the Plan app's generation pipeline) still lacked the fix, so it was systemic to any long-running Anthropic-backed generation, not specific to wireframes.

Solution

Reuse the existing shared predicate (isBareProviderRejectionMessage) — already used by the Builder gateway engine and the AI SDK lane — in the Anthropic engine so all three lanes agree on the same verdict for a reasonless 403. A 403 with no discernible reason is now tagged with PROVIDER_TRANSIENT_REJECTION_ERROR_CODE and providerRetryable: true, letting the run retry with backoff and surfacing a human-readable, retryable message instead of a bare HTTP status echo. A 403 that carries an actual reason (e.g. permission_error) still keeps http_403 and the credential lane.

Key Changes

  • anthropic-engine.ts: detect a bare/empty-reason 403 via isBareProviderRejectionMessage and tag it with PROVIDER_TRANSIENT_REJECTION_ERROR_CODE + providerRetryable: true instead of http_403, while 403s with a real reason keep existing credential-lane behavior.
  • Added bare-forbidden-parity.spec.ts: regression coverage asserting that the Anthropic engine, the AI SDK lane (classifyProviderError), and the run-loop's retry/continuation logic all agree that a bare 403 is transient and retryable, that a reasoned 403 stays on the credential lane, and includes a static guard that fails if any future *-engine.ts file maps `http_${status}` without consulting the shared predicate.
  • Added changeset anthropic-bare-403-transient.md documenting the fix as a patch to @agent-native/core.

Notes

  • No duplicate/related Factory items or PRs about Plan generation 403s or "Working" hangs were found to reference.

Edit in Builder  Preview


To clone this PR locally use the Github CLI with command gh pr checkout 5041

You can tag me at @BuilderIO for anything you want me to fix or change

…ejected credential

The Anthropic engine tagged every provider HTTP status `http_<status>`, so an
empty-body "403 status code (no body)" ended the turn on its first occurrence,
discarded the partial answer, and routed a working credential onto the
"reconnect your provider" lane. The Builder gateway engine and the AI SDK lane
already classify that exact wording as a transient rejection; the Anthropic
engine now shares the same predicate, so the run retries with backoff and a
turn that stays refused reports a retryable sentence instead of a bare HTTP
status echo. A 403 that carries a real reason keeps `http_403`.
@builder-io-integration builder-io-integration Bot changed the title fix(core): treat a reasonless Anthropic 403 as load-shedding, not a rejected credential Treat bare Anthropic 403 as transient, not a credential failure Sep 15, 2026
builder-io-integration[bot]

This comment was marked as outdated.

@steve8708

Copy link
Copy Markdown
Contributor

@builderio-bot look at the latest PR feedback and fix anything you agree with. Be skeptical.

Reply in each open inline thread with exactly one of:

  • Required — fixed: …
  • Required — not fixing: …
  • Optional — skipping: …

Or resolve the thread in GitHub. Outdated threads after new commits do not need a new reply.

Get CI green and keep the branch mergeable.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Builder reviewed your changes — looks good ✅

Review Details

Incremental Code Review Summary

I reviewed the current PR #5041 head after the update. The changed scope remains the Anthropic engine's handling of reasonless 403 responses, the shared retry/continuation classification, parity regression coverage, and the core changeset. The implementation still classifies an empty-reason 403 as transient and retryable while preserving credential-lane behavior for reasoned 403 responses and explicit non-retryable SDK verdicts.

This remains a standard-risk core behavior change. Two independent balanced incremental reviews found no new actionable issues, and the relevant parity plus Anthropic/error-classification suites passed. There were no previous inline findings to resolve or avoid resubmitting. The current diff has no user-interface changes.

🧪 Browser testing: Skipped — PR only modifies core provider/error handling, tests, and release metadata; no browser/UI surface changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants