Error Handling — Frontend

Field Details
Status Active
Last Updated 05-12-2026

Purpose

Consistent, user-friendly error handling across all frontend apps.


Scope

Applies to: All frontend applications Does not apply to: Backend services, third-party libraries


Rules

  • Never silently catch errors — log them or show feedback
  • Always show a human-readable message — never raw errors or stack traces
  • Handle API errors through a shared wrapper
  • Use error codes from Error Codes — never invent new ones in UI

Async / Try-Catch — always handle, never hang

Every async call must have a try/catch. Don't let a promise fail silently.

async function submitInvoice(data: InvoiceData) {
  try {
    setLoading(true)
    setError(null)
    await api.createInvoice(data)
  } catch (err) {
    setError(toUserMessage(err))
  } finally {
    setLoading(false)
  }
}

Nested async calls

When one async function calls another, don't wrap every level in try/catch. Let the inner function throw, and catch it once at the top (usually where the UI lives).

// Inner — just throws, no try/catch
async function fetchInvoice(id: string) {
  const res = await fetch(`/api/invoices/${id}`)
  return handleApiResponse<Invoice>(res)   // throws on failure
}

// Middle — also just throws
async function loadInvoiceWithItems(id: string) {
  const invoice = await fetchInvoice(id)
  const items   = await fetchItems(invoice.id)
  return { invoice, items }
}

// Top (UI) — the ONLY place that catches
async function onOpenInvoice(id: string) {
  try {
    setLoading(true)
    const data = await loadInvoiceWithItems(id)
    setInvoice(data)
  } catch (err) {
    setError(toUserMessage(err))
  } finally {
    setLoading(false)
  }
}

Rule of thumb: catch where you can do something about it (show a message, retry, redirect). Everywhere else, just await and let it bubble up.

If you start a promise without awaiting it (fire-and-forget), always attach .catch:

trackEvent("invoice_opened").catch((err) => logger.error("tracking failed", err))

Form Validation — field-level only

Show the specific field issue. Never show a generic "something went wrong" for validation.

{errors.email && <span className="field-error">{errors.email}</span>}

Exceptions

None. Every interaction must handle failure gracefully.



Changelog

Version Date Author Change
1.0.0 05-12-2026 Tibin Sunny Initial version