[Bug] Claude Desktop fullscreen "Claude will return soon" fallback caused by React TypeError: e.replace is not a function (errorCode 1GY780K) when rendering numeric MCP tool-result fields
Severity: High — poisons any conversation whose history contains the triggering tool result. The fullscreen fallback's "Try again" button re-mounts the same crashing component, so it loops. Only
recovery is Cmd+Q and relaunch; reopening the poisoned chat re-triggers it immediately.
Environment:
- Claude Desktop 1.3883.0 (macOS, Darwin 25.4.0)
- Renderer bundle at the time of filing: index-2Bphe_Ab.js (vendor vendor-P0aQfEyr.js). Error has recurred across at least 11 distinct frontend bundle hashes in my local claude.ai-web.log, so it has
survived multiple deploys.
- MCP server: third-party local stdio server that returns JSON numbers in tool-result fields. The bug is reproducible with any MCP server whose tool-result JSON contains a numeric field.
Symptom:
When an MCP tool returns a response containing numeric fields (e.g. a float like 0.2800000011920929), the claude.ai web app renderer throws TypeError: e.replace is not a function inside a useMemo.
The [BOOTSTRAP] Fatal error boundary catches it and renders the fullscreen "Claude will return soon. Claude is currently experiencing a temporary service disruption. We're working on it, check back
soon" screen with a non-functional "Try again" button. The error-boundary text is misleading — there is no service disruption; this is a client-side unhandled exception.
Closing and reopening Claude Desktop recovers, but reopening the affected conversation re-renders the same message history and crashes again instantly. New chats stay clean until an MCP tool call
produces the same response shape, at which point that chat also becomes permanently poisoned.
Evidence from ~/Library/Logs/Claude/claude.ai-web.log (most recent entry, 2026-04-23 09:51:26):
[error] [BOOTSTRAP] Fatal error boundary triggered
{
"errorMessage": "e.replace is not a function",
"errorCode": "1GY780K",
"url": "/chat/a9268f10-b41a-42b1-af14-969237a65738",
"errorStack": "TypeError: e.replace is not a function
at Jtt (https://assets-proxy.anthropic.com/claude-ai/v2/assets/v1/index-2Bphe_Ab.js:21:551191)
at rnt (.../index-2Bphe_Ab.js:21:553532)
at Upt (.../index-2Bphe_Ab.js:23:404506)
at Kpt (.../index-2Bphe_Ab.js:23:409463)
at .../index-2Bphe_Ab.js:23:596125
at Object.Xi [as useMemo] (.../vendor-P0aQfEyr.js:11:61312)
at Ea.ka.useMemo (.../vendor-P0aQfEyr.js:2:68085)
..."
}
Probable root cause:
.replace() is being called on a value that is a JSON number rather than a string. The frame order suggests a useMemo that formats a tool-result field — likely stripping trailing zeros or formatting a
display value — without first checking/coercing the type. Example MCP tool response that triggers it:
{
"name": "Engine B Delay",
"value": 0.11999999731779099,
"normalized_value": 0.12,
"display_value": "2.07 ms",
"is_quantized": false,
"clamped": false
}
value and normalized_value are JSON numbers. The MCP spec does not require tool-result fields to be strings, so the frontend assumption is a bug.
Reproduction:
- Configure any local stdio MCP server in Claude Desktop that returns at least one numeric field in a tool-call result (a minimal tool returning {"value": 0.28, "normalized_value": 0.28,
"display_value": "28 %"} suffices).
- Invoke that tool from a Claude Desktop chat.
- The fullscreen "Claude will return soon" fallback appears within ~1 second of the tool response being rendered.
- Reopening the same conversation re-triggers the fallback on every mount.
Suggested fix (two separate):
- The actual bug: wherever the crashing useMemo coerces a tool-result field, guard the .replace() call — either String(v).replace(...) or typeof v === "string" ? v.replace(...) : v. Same guard
should apply to any other string method called on tool-result fields.
- The error-boundary UX: the "Try again" button currently re-mounts the same broken subtree and so loops forever. The fallback should at minimum allow the user to navigate away from (or delete) the
poisoned chat without relaunching the app. The displayed text should not say "service disruption" for client-side render errors — that misleads users into waiting for an outage that isn't happening.
Related bug, same app (file as a separate issue or note in the same report — your call):
The yellow "Tool result could not be submitted. The request may have expired or the connection was interrupted. Refresh the page to continue." popup is caused by POST
/api/organizations/<org>/chat_conversations/<uuid>/tool_result returning HTTP 404 from the claude.ai backend. Visible in the same renderer log as QueryClient error:
{"type":"not_found_error","statusCode":404,"endpoint":"/api/organizations/.../tool_result"}. The user-facing message misattributes this — it is not a timeout or connection drop, it is a 404 on the
submission endpoint.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗