Agents will happily ship an empty state that looks right: illustration slot, primary button, secondary link. The string inside is often the bug — “Oopsie! No data found!!” next to a finance table, or “You haven’t created anything yet” when the user lacks permission, not motivation.

I’ve started reviewing empty-state copy for tone as its own checklist item, separate from layout. The component can be perfect and still speak in the wrong register.

What goes wrong in AI empty copy

Patterns that show up constantly:

  • Blame — “You haven’t…”, “You failed to…”, when the system or permissions are the real cause
  • Fake cheer — “Awesome!”, “Oopsie!”, emoji piles in a product that otherwise speaks calmly
  • Jargon — “No entities hydrated”, “Zero rows in projection”
  • Dead ends — witty line, no next step
  • Wrong audience — engineer voice in a customer admin, or marketing voice in an internal tool
  • Lying specificity — “Upload a CSV” when the empty state is actually a filter with zero matches

Layout review won’t catch these. Reading the string aloud in the product’s normal voice will.

A short tone pass (five questions)

Before you merge:

  1. Cause — Is this empty because of filters, permissions, first-run, or true zero data? Does the copy match that cause?
  2. Agency — Does the user have a clear next action, or only a shrug?
  3. Register — Would this sentence appear in a normal success toast in this product? If not, why is empty louder?
  4. Blame direction — Are we accusing the user of inaction when the API returned 403?
  5. Length — Can title + one supporting line + one CTA carry it? Agents love paragraphs.

If any answer is fuzzy, rewrite the strings before debating border radius.

Side-by-side: same empty, different tone

Filter miss on invoices:

Copy
Weak "Oopsie! Nothing here 😅 Get started by creating your first invoice!"
Stronger "No invoices match these filters." / "Clear filters to see all invoices."

Permission empty on the same page:

Copy
Weak "You haven’t created anything yet."
Stronger "You don’t have access to invoices." / "Ask an admin for billing access."

Same component shell. Different cause. Different strings. Tone review is noticing that swap before merge.

Prompt that produces usable copy

Write empty-state copy for FilteredInvoices when the filter match count is 0. Product voice: calm, direct, no emoji, no “oops”, second person sparingly. Cause: active filters, not first-run and not a permissions block. Need: - title ≤ 6 words - supporting line ≤ 20 words that mentions filters - primary CTA label for clearing filters (use existing clearFilters action) - no joke, no exclamation marks, no “get started” (wrong cause) Also provide a second variant for permission-denied empty (separate story), same voice rules. Do not invent features we don’t have. 

Cause separation is the whole game. One mega-string for “any empty” is how you get first-run CTAs on a filter miss.

Review table I keep in the PR

State Title Supporting CTA Tone OK?
Filters empty … … Clear filters
First-run … … Create invoice
Forbidden … … Request access / contact admin

If the agent only generated Default empty, ask for the missing causes as separate stories or copy variants — don’t merge a single cheerful string that covers none of them well.

Reject / send back

Reject

  • “Oops” / “Uh-oh” / stacked emoji in a serious product surface
  • Blame-the-user framing for system or permission empties
  • CTA that routes somewhere the empty state can’t actually fix
  • Lorem / placeholder still in the tree (“Your catchy empty title here”)
  • One string reused for filter-empty and first-run

Accept

  • Cause-accurate wording
  • Voice consistent with neighboring toasts / errors
  • One clear action (or an honest “no action available” for true read-only empties)
  • Strings reviewed as copy, not only as props in a Storybook Control

Tiny habit

When an agent PR adds an empty state, open the story and read only the text — ignore the illustration for one pass. If you wouldn’t ship that sentence in a support email, don’t ship it in the component. Fix tone before you argue about the SVG.