A silently frozen chat UI after an API failure leaves users without any signal: they do not know whether to retry, wait, or refresh. Worse, mishandled error paths frequently leak raw error objects — stack traces, internal route names, or upstream provider error messages — directly into the rendered output, which CWE-209 (Generation of Error Message Containing Sensitive Information) identifies as an information-disclosure risk. In subscription products, a broken interface with no error message or retry affordance is an immediate churn signal. The combination of user confusion, potential data exposure, and broken UI state makes silent failure the worst possible error-handling outcome.
Critical because a missing error handler can freeze the UI with `isLoading` stuck as true and may expose raw error objects containing sensitive internal details to end users.
Add an error state guard to src/components/chat/ChatWindow.tsx that renders a human-readable message with a retry action. Never surface raw error objects.
{error && (
<div className="bg-destructive/10 text-destructive p-3 rounded-md text-sm">
<p>Something went wrong. Please try again.</p>
<Button onClick={reload} variant="outline" size="sm" className="mt-2">
Retry
</Button>
</div>
)}
For the Vercel AI SDK useChat hook, wire the onError callback to your observability platform (console.error in development, a structured logger in production) so errors are recorded without being echoed to the user.
ID: ai-chat-visibility.error-handling.api-error-user-message
Severity: critical
What to look for: Count all error handling paths in the chat API call on the frontend: .catch() handlers, try/catch blocks, onError callbacks (the Vercel AI SDK's useChat accepts an onError option), and conditional rendering based on an error state variable. For each error handler found, classify whether it renders a user-visible message or silently swallows the error. Quote the actual error rendering JSX if found.
Pass criteria: When the AI API call fails (network error, 4xx, 5xx response), a human-readable error message appears in the chat interface. The error is visually distinct from regular messages (different styling or color). At least 1 error handler must render a visible UI element.
Fail criteria: API errors result in a silent failure (UI appears frozen), a raw error object dump in the chat, or an unhandled Promise rejection that leaves the UI in a broken state.
Skip (N/A) when: No AI chat interface is detected. Signal: same as response-streaming-progressive.
Detail on fail: "No error state rendering found in chat component — API failures silently leave the UI frozen with isLoading stuck as true"
Remediation: In your chat component at src/components/chat/ChatWindow.tsx, render error state:
{error && (
<div className="bg-destructive/10 text-destructive p-3 rounded-md">
<p>Something went wrong. Please try again.</p>
<Button onClick={reload} variant="outline" size="sm">Retry</Button>
</div>
)}
Never expose raw error objects or stack traces to users. Log errors to your observability platform instead.
Cross-reference: For a deeper analysis of error handling architecture, the SaaS Error Handling Audit in the SaaS Reliability Pack covers server-side error management and logging in detail.