Anthropic news, April 15, 2026, read from 100 lines of a TypeScript catch block
On Wednesday April 15, 2026, two Anthropic stories ran side by side. Claude was down across claude.ai, the API, and Claude Code until roughly 1:42 PM ET. Mythos, the held-back model, had Treasury Secretary Scott Bessent summoning Wall Street leaders the same morning. Every roundup led with one or both. This page leads with what a consumer Mac app does with the error responses those outages produce, because that is where the April 15 downtime actually lived for the users of downstream tools.
What every April 15 roundup covered
The first-page search results for "anthropic news april 15 2026" are a short list and they all point the same way: the outage, the Mythos holdback, the TrendAI partnership, the IPO sentiment piece. Good coverage. None of it describes what the outage actually did to a downstream app.
What those roundups do not mention
The downstream gap
- None describe how a downstream app actually classifies Anthropic API errors during an outage.
- None distinguish structured errorType=rate_limit from the English string 'rate limit rejected'.
- None cite the HTTP status branches an app must recognize (402 billing, 429 rate limit, 503 overloaded, 401 auth).
- None mention retry budgets, which is the only thing that separates a stuck spinner from a visible error.
- None show the typed event shape the app UI consumes when the network layer surfaces a typed failure.
The anchor fact
A hundred lines of TypeScript decides what the chat window shows during a Claude outage.
The file is acp-bridge/src/index.ts. The classification block runs roughly lines 1893-1999. The api_retry ingestion that populates the structured error buffer is at 2468-2478. Two constants cap the retries: MAX_AUTH_RETRIES = 2 at line 808 and MAX_QUERY_RETRIES = 2 at line 1385. That is the entire contract between Anthropic's API errors and a Fazm user's chat bubble. It is why, during the April 15 incident, a Fazm user saw a real error and not a spinner that never resolved.
- ▸Line 808: const MAX_AUTH_RETRIES = 2 - caps OAuth retry loops on 401s.
- ▸Line 813-814: let lastApiRetry - the structured error buffer populated by the patched ACP SDK.
- ▸Line 1385: const MAX_QUERY_RETRIES = 2 - caps the outer session-resume loop.
- ▸Line 1901-1903: the exact structured-plus-regex credit detector (402, 429, billing_error, rate_limit, or fallback regex).
- ▸Line 1914: sendWithSession(sessionId, { type: credit_exhausted, message: errMsg }) - the user-visible billing event.
- ▸Line 1966: sessionRetryCount capped at 1 inside the resume-the-same-session branch.
- ▸Line 1995: sendWithSession(sessionId, { type: error, message: errMsg }) - the surface-the-raw-string branch.
- ▸Lines 2468-2478: the api_retry case that populates lastApiRetry before handleQuery's catch ever reads it.
The retry budget, by the numbers
Four hard caps. A Fazm chat that runs into an Anthropic outage spends at most three attempts (one initial, up to two retries) and surfaces at most one of four typed events to the UI. That is the contract. These count up from zero as you scroll them into view.
For scale, the Anthropic status update that closed the April 15 incident at 0 (13:42 ET) covered elevated errors on three surfaces: claude.ai, the API, and Claude Code. All three failures land on the same four event types in a Fazm chat.
How an Anthropic error reaches a chat bubble
Three inputs (a failed POST from Anthropic, a typed api_retry update from the patched SDK, and a raw JavaScript Error at the end of the retry chain) converge on one classifier inside the ACP bridge. That classifier picks one of four typed events and forwards it to the Fazm chat window.
Anthropic failure -> acp-bridge classifier -> chat UI
The structured path wins, the regex is a safety net
This is the classification block verbatim (trimmed for readability, but every conditional and every event name is real). The structured branch reads lastApiRetry first. Only if that is null or ambiguous does the regex look at English error strings.
The outage, as a sequence diagram
One user prompt, four actors, nine messages. Two of those messages are errors, two are typed events back to the Fazm UI. At no point does the chat window sit blank waiting for a response that will never come.
April 15 outage - request path through Fazm
Where the structured error data comes from
The classifier above trusts lastApiRetry as if it were already there. The code below is what puts it there: a separate case block further down in the same file, listening for api_retry updates emitted by the patched ACP SDK entry point (acp-bridge/src/patched-acp-entry.mjs). Every retryable Anthropic failure gets seen here first.
The four typed events a Fazm chat can receive during an incident
Every failure mode collapses to one of these four shapes. The UI has four branches, not twelve, and no default catch-all for unknown errors. Unknown means something leaked past the classifier, and that is a bug, not a user-facing state.
api_retry
Fires every time the patched ACP SDK emits a retry signal. Carries httpStatus (may be null for transport errors), errorType (billing_error, rate_limit, invalid_request, image_error, api_error, overloaded, unknown), attempt, maxRetries, and retryDelayMs. Fazm UI uses it to show a retry hint without killing the existing message stream.
credit_exhausted
Fires only for HTTP 402, HTTP 429, errorType=billing_error, or errorType=rate_limit. The UI renders a billing/limits banner with the raw server message. Does NOT retry. lastApiRetry is cleared. This is the event that keeps a user from burning through their API budget retrying a 429 into the void.
error
The everything-else branch. Fires when the error is non-retryable but also not credit or rate limit. The message is surfaced raw so the user sees what Anthropic actually said. On an April 15 style outage, this is what a user saw after the retry budget was spent.
tool_activity
Not a failure event, but critical during a failure. Every pending tool call at the moment of failure gets { status: 'completed' } so the UI does not leave a fake 'Browser running...' or 'Reading file...' spinner behind. The bridge sweeps pendingTools in every failure branch.
The April 15 outage, from Fazm's perspective
Five moments between Anthropic's first status update and the resolution at 1:42 PM ET. None of them required a Fazm release, an app restart, or a login flow.
10:32 AM ET - Anthropic status page posts 'elevated errors'
The first public signal. claude.ai, api.anthropic.com, and Claude Code all start returning a mix of 5xx and partial responses. Downstream clients begin seeing session/prompt rejections. In Fazm, the ACP SDK on a user's machine catches the failure, emits an api_retry update with httpStatus populated, and lastApiRetry gets set inside the bridge. The typed error is a server-side 5xx, not a billing or rate-limit code.
Seconds later - Fazm fires api_retry to the UI
The UI shows a subtle 'retrying...' hint with the attempt number and retry delay. No spinner-of-death. The information is typed, not prose: { type: 'api_retry', httpStatus: 503, errorType: 'api_error', attempt: 1, maxRetries: 2, retryDelayMs: 2000 }. If the user cancels at this point they see a partial result, not a stuck state.
Retry budget exhausted - structured classifier takes over
The outer handleQuery catch fires. apiRetryErrorType reads 'api_error' (not 'billing_error', not 'rate_limit'). apiRetryHttpStatus reads 503 (not 402, not 429). isStructuredCreditError is false. isRegexCreditExhausted is false. The code falls through to the session-resume retry path, which is gated by sessionRetryCount === 0. One resume attempt, no second.
Resume fails - error surfaces to the chat bubble
The second attempt also fails because api.anthropic.com is still flaky. The final branch fires { type: 'error', message: errMsg } to the UI, and every pending tool gets a 'tool_activity completed' event so no call appears orphaned. The user sees the real server message in the chat, not a polite platitude. They press Stop or wait.
1:42 PM ET - Anthropic marks the incident resolved
The next user message flows through the same bridge. No state reset, no OAuth re-auth, no login dialog. The session file in ~/.claude/projects/ is still valid (or Fazm's resume path would have fetched a fresh one). lastApiRetry was cleared at line 1915 after the credit branch or line 1997 after the generic-error branch. First tokens stream back. Users never learned there was a bridge between them and the outage; they just learned there was a bridge.
The bridge-to-UI contract, typed
The Swift chat view does not inspect English. It switches on a discriminated union. Every field shown below is what the acp bridge actually serialises over its JSON line protocol. The Swift side decodes it into a typed value and renders accordingly.
Verify the line numbers yourself
A repo checkout and three shell commands. If the line numbers on this page are stale, this is how you catch it. The output below was captured on 2026-04-20.
The local layer kept working
The half of Fazm that reads macOS accessibility trees (the AXUIElement calls, the AXObserver thread, the focused-app watcher) did not notice the April 15 outage. That layer does not talk to Anthropic. It talks to Apple's Accessibility APIs, running in-process on the user's Mac. The cursor position, the currently focused window, the contents of the frontmost textfield: all still visible to Fazm during the incident. Only the Claude-backed reply generation was blocked, and even that was blocked honestly (typed error, visible message) rather than quietly.
That separation is why consumer AI apps that rely on screenshots-plus-vision have a harder outage story than apps that use accessibility APIs. A vision-based pipeline needs the model to interpret a screenshot even to tell you what button is on screen. Fazm reads the button from the accessibility tree. During an outage, a vision-first app goes dark on perception as well as action. Fazm only goes dark on action. That is a small difference on a good day and a very large one on April 15.
The point is not that Fazm handled the incident heroically. It is that the incident exposed a boundary that always exists in a consumer AI app, between the model layer (which you do not own) and the perception layer (which you do). The acp bridge's classifier is the code that makes that boundary visible. It refuses to swallow errors and refuses to retry forever. That is the part of April 15 worth reading.
Want the typed-error contract in your own Claude-powered app?
I will walk through Fazm's ACP bridge, the api_retry ingestion path, and the four event types on a 20-minute call.
Book a call →Anthropic news April 15 2026 FAQ
What was the Anthropic news on April 15, 2026?
Two stories ran in parallel. The operational story: Claude experienced elevated errors across claude.ai, the API, and Claude Code, with the incident marked resolved by Anthropic at roughly 1:42 PM ET. The policy story: Anthropic's Mythos model stayed held back for safety review, and US Treasury Secretary Scott Bessent summoned Wall Street leaders to confirm their systems were defended against it. The outage affected every downstream app that talks to api.anthropic.com, including chat clients, editor extensions, and Mac assistants like Fazm. This page is about the downstream side of that outage, not the headline side.
What does Fazm actually do when Claude is down?
Fazm's ACP bridge (the TypeScript subprocess that speaks the Agent Client Protocol to the Claude agent binary) has a typed error-handling pipeline in acp-bridge/src/index.ts. When a session/prompt call fails, the bridge first reads the last api_retry update (HTTP status code plus a typed errorType like billing_error, rate_limit, invalid_request, or image_error). If the status is 402 or 429, or the errorType says billing_error or rate_limit, the bridge fires a typed credit_exhausted event to the UI and does not retry. For everything else that looks retryable, it resumes the same session once (sessionRetryCount capped at 1) and then gives up, surfacing the raw error string to the chat window. The user sees the real reason. There is no infinite spinner.
Where in the Fazm source is this logic?
Desktop/../acp-bridge/src/index.ts in the Fazm monorepo. The relevant constants are MAX_AUTH_RETRIES = 2 at line 808 and MAX_QUERY_RETRIES = 2 at line 1385. The lastApiRetry state declaration is at line 813 and 814. The main classification block runs from roughly line 1893 to line 1999 inside handleQuery. The api_retry ingestion (which populates lastApiRetry whenever the patched ACP SDK emits a retry event) is a separate case block at lines 2468 to 2478. The patched ACP entry point that actually emits those api_retry events is acp-bridge/src/patched-acp-entry.mjs.
Why does structured error info beat regex-matching the error string?
Because error strings from Anthropic's API drift over time, and a consumer app that pattern-matches on English sentences is one copy-edit away from a regression. When the Anthropic SDK started emitting structured error events (HTTP status code plus a typed category), Fazm started reading those first and only fell back to regex when the structured data was missing. On April 15 specifically, an outage that returns a 503 with no familiar English string still gets correctly classified as non-credit and non-rate-limit, because the structured path sees httpStatus=503 and errorType=api_error (not billing_error and not rate_limit). The regex path would have missed that entirely and silently retried into the hole.
What is the retry budget on a failed Claude query?
Three attempts, at most. MAX_AUTH_RETRIES = 2 (line 808) bounds OAuth flows when Claude returns 401. MAX_QUERY_RETRIES = 2 (line 1385) bounds the outer resume/session-new loop. sessionRetryCount (a per-query counter) is capped at 1 as a safety net against infinite loops inside a single session/prompt call. That gives a hard ceiling on how long a user waits during an outage. On April 15 a Fazm chat that ran into Anthropic's elevated errors would have done one resume attempt at most and then shown the raw server message in the chat bubble.
What typed events can the Fazm chat UI receive during an outage?
Five. (1) api_retry with httpStatus, errorType, attempt, maxRetries, and retryDelayMs fields, which the UI renders as a subtle 'retrying...' hint. (2) credit_exhausted with the raw error message, which the UI surfaces as a billing or rate-limit banner. (3) error with a raw string, used for everything non-billing and non-rate-limit that the bridge decides not to retry. (4) tool_activity with status='completed' for every pending tool when a query aborts, so no spinner is left hanging. (5) result with the partial text accumulated so far if the user pressed Stop during the failure. The chat window never shows a ghost state. Either tokens keep streaming, or a typed event lands and the UI renders a real message.
Is this specific to Claude, or does Fazm handle any model provider this way?
Specific to Claude via the ACP protocol. Fazm speaks Agent Client Protocol to the Claude agent binary; that protocol is where api_retry updates originate. Other providers (OpenAI, Gemini, Bedrock direct) would need their own typed pipeline if Fazm ever bolted them on. The reason this matters is that on April 15 the outage was specifically Anthropic's, and Fazm's bridge has Anthropic-shaped knowledge of what a transient 503 looks like versus a 402 versus a 429. A provider-agnostic shim would have had to guess.
How does this relate to Fazm's accessibility-API architecture?
It is the other half. Fazm reads the Mac's accessibility tree (AXUIElement, AXObserver, the kAX* keys) to perceive any app on the screen, not just a browser. That is the local perception layer. The acp-bridge pipeline described on this page is the cloud inference layer. They are independent. A Claude outage freezes the cloud layer; the local accessibility layer still works, which is why Fazm's read-only features (showing what app the user is in, reading clipboard, observing focused UI) keep working even during an Anthropic incident. Only the reply generation is blocked. The moment Anthropic marks the incident resolved and api.anthropic.com returns 200, the next user message flows through the same bridge with no state reset.
Can I verify the line numbers on this page?
Yes. Clone the public Fazm repository and run `grep -n 'MAX_QUERY_RETRIES\|MAX_AUTH_RETRIES\|lastApiRetry' acp-bridge/src/index.ts`. You should get matches at lines 808, 813, 814, 1385, and several uses through 2475. The full classification block is visible with `sed -n '1893,1999p' acp-bridge/src/index.ts`. The api_retry ingestion case is `sed -n '2468,2478p' acp-bridge/src/index.ts`. All line numbers are as of 2026-04-20 on the main branch.
Comments (••)
Leave a comment to see what others are saying.Public and anonymous. No signup.