Advanced

API error fallback

When the ledger returns 500, the UI shows a stable error surface without crashing the route.

User story

As a quality engineer, I want the UI to degrade gracefully on 500 responses so users never see a blank page.

Acceptance criteria

  • 500 response renders an error region
  • App shell + nav remain visible
  • Retry button refetches the route
  • Error boundary does not bubble

Manual test steps

  1. 1.Set up route to return 500
  2. 2.Open /wallet
  3. 3.Assert error surface

Expected result

Error region reads 'Wallet service unavailable' and a Retry CTA is present.

Possible bug risks

  • Whole app crashes via uncaught error
  • Retry CTA loops forever without backoff
  • Logs leak the entire error stack to the user

Reference Playwright spec

api-error-fallback.spec.ts
ts
1
2
3
4
5
6
7
8
9
10
11
import { test, expect } from '@playwright/test';

test('500 surfaces stable error region @regression', async ({ page }) => {
  await page.route('**/api/ledger/balance', (route) => {
    route.fulfill({ status: 500, body: JSON.stringify({ error: 'ledger_timeout' }) });
  });

  await page.goto('https://lab.hakdogan.com/wallet');
  await expect(page.getByText(/wallet service unavailable/i)).toBeVisible();
  await expect(page.getByRole('button', { name: /retry/i })).toBeVisible();
});