# Errors Include the Fix

**MUST** · **ID:** `content-actionable-errors` · **Category:** content
**Source:** [Vercel](https://github.com/vercel-labs/agent-skills/blob/main/skills/web-design-guidelines/SKILL.md)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/content-actionable-errors

> MUST: Every error message states the fix, not just the problem: the expected format, the missing permission, or a link/button to the place the user can resolve it.

State what went wrong, what correct looks like, and give the user the next step

An error that only names the problem ("Invalid input") leaves the user guessing which of several rules they broke. Pair the diagnosis with a concrete remedy — the expected format, the missing permission, a link or button to the place where they can fix it — so the message ends the dead end instead of announcing it.

## Bad — do not do this

`content-actionable-errors-bad`

```tsx
export function ActionableErrorsBad() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4 space-y-3">
        <label htmlFor="err-key-bad" className="text-sm font-medium text-foreground">
          API Key
        </label>
        <input
          id="err-key-bad"
          defaultValue="pk_live_8fj2..."
          aria-invalid="true"
          className="w-full px-3 py-2 text-sm bg-background border border-error rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
        />
        <p className="text-sm text-error">Error: invalid input.</p>
      </div>
      <p className="text-xs text-error">
        Names the problem and stops. The user is left guessing what "invalid"
        means, and there is nothing to click
      </p>
    </div>
  );
}
```

## Good — do this

`content-actionable-errors-good`

```tsx
export function ActionableErrorsGood() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4 space-y-3">
        <label htmlFor="err-key-good" className="text-sm font-medium text-foreground">
          API Key
        </label>
        <input
          id="err-key-good"
          defaultValue="pk_live_8fj2..."
          aria-invalid="true"
          aria-describedby="err-key-good-msg"
          className="w-full px-3 py-2 text-sm bg-background border border-error rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
        />
        <p id="err-key-good-msg" className="text-sm text-error">
          This is a publishable key. Secret keys start with{' '}
          <code className="px-1 bg-muted rounded">sk_live_</code> — copy one
          from the dashboard.
        </p>
        <button className="px-3 py-2 bg-primary text-primary-foreground text-sm rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring">
          Open Key Dashboard
        </button>
      </div>
      <p className="text-xs text-success">
        Says what's wrong, what correct looks like, and gives the user the next
        step as a control
      </p>
    </div>
  );
}
```

## References

- [Vercel Web Interface Guidelines](https://github.com/vercel-labs/web-interface-guidelines)
- [NN/g: Error Message Guidelines](https://www.nngroup.com/articles/error-message-guidelines/)
