Error

Good error design is clear, useful, and friendly. Designing concise and accurate error messages unblocks users and builds trust by meeting people where they are.

Default

Custom label

No label

Sizes

With an error property

Best Practices

When to use

  • Use the Error component as a block surface when a section or page-level resource failed to load: a panel, a dashboard card, a route boundary.
  • Pick toasts.error() for transient action failures (Couldn’t save settings. Try again.) and the error prop on Input for field-level validation. Don’t replace either with this block.
  • Always pair platform or system errors with a stable identifier (request ID x-vercel-id, deployment ID dpl_…, run ID, trace ID). Validation and permission denials are user-state, not system, and don’t need an ID.

Behavior

  • The recovery action must do something concrete: a Try Again button when the operation is retry-safe, a named verb (Reconnect GitHub, Update Payment Method) when it isn’t.
  • Don’t auto-retry in the background; the user came to this surface to decide.
  • For full-page route errors (error.tsx), return focus to the Try Again button on appearance so a keyboard user can retry without hunting for it.

Content

  • State what happened and what to do next, in that order. Cut apologetic preambles (Unfortunately, Oops, We’re sorry).
  • Use Couldn’t or Can’t for user-state errors (Couldn’t verify your passkey. Try again.); use Failed to for system or infra errors that mirror CLI output (Build failed. Bundle exceeds 50 MB.). Unable to is banned.
  • Don’t fall back to Something Went Wrong as a title; name the resource that failed (Couldn’t Load Page, Couldn’t Load Deployments).
  • Render the stable ID on a monospace sub-line under a collapsed <details> so the user can copy-paste it into a support thread.
  • Never humor an error. Users hitting an error are frustrated; insincere copy makes it worse.

Accessibility

  • When the error appears asynchronously (after a failed fetch), wrap the region in aria-live="polite" so it’s announced. Reserve aria-live="assertive" for true blocking errors that interrupt input.