Skip to main content

Command Palette

Search for a command to run...

The reader of your error message was never in the room

Most error states are written for the person watching the run. The one who actually needs them shows up months later, cold, with none of your context. Design for that stranger and the spec changes completely.

Updated
5 min read
The reader of your error message was never in the room
R
Freelance web developer from the Kansai region of Japan. I build WordPress plugins (Rapls AI Chatbot, Thanks Mail for Stripe, Rapls PDF Image Creator) and write about AI coding tools, Claude Code, and the security side of shipping with LLMs. I work in public and write down what breaks. Blog: https://raplsworks.com

When you write an error message, you picture a reader. Almost always it's you, at the terminal, right now, watching the thing fail. And for that reader a terse message is fine, because they already hold all the context. validation failed at step 3 is enough when you know what step 3 was, what you changed, and what the run was supposed to do.

The trouble is that this reader is rarely the one who actually needs the error. The person who needs it shows up much later, knows none of what you know, and may never have seen the system before. Design for them and almost everything about the error state changes. A long comment thread on an earlier post is what talked me into taking that seriously, especially for the unattended, agent-driven work I lean on now.

Two readers, two completely different specs

An interactive failure has a human in the loop. The context is live, the conversation is right there to scroll back through, the fix is a minute away. A short message works because it points at things both of you already know.

Unattended work has none of that. An agent runs a pipeline overnight, something breaks halfway, and nobody watches it land. No replay, no conversation history, no warm context in anyone's head. Whoever investigates arrives cold, hours or weeks later, holding only whatever the process wrote down before it stopped.

For that reader the error state stops being a report about the failure. It is the failure, as far as they can ever see it. If the record doesn't carry what they need to reconstruct the run, the information isn't buried somewhere. It's gone. So the design question quietly changes from "how do I format this error" to "what would a stranger need to rebuild this from nothing," and those two questions have very different answers.

A message points; a record carries

The shortest way I can name the split: most errors are a message, and unattended work needs a record.

A message is for someone who shares your context. It can be short because it leans on knowledge you both have. A record is for someone who has nothing, so it has to carry the context with it: what the input was, what stage this happened in, what the system believed was true when it chose to proceed, what was retried and with what result. A record is deliberately heavier, because its entire job is to survive the gap between the moment of failure and the person who reads about it later.

The check I use now is blunt. If I deleted the rest of the system and handed someone only this error state, could they tell me what went wrong? If the answer depends on context stored anywhere but the record itself, I've written a message and labelled it a record.

Time isn't the only gap; people are

There's a second reason the later reader arrives empty-handed, and it isn't only the passage of time. It's turnover.

The person who built the system often isn't the one debugging it three months on. They changed teams, changed jobs, or simply moved on and let the context fade. So the investigator isn't even future-you, who at least once shared your assumptions. It's someone who was never in the room when the decisions were made, meeting your system for the first time through its failure. If the error state only parses for someone who already understands the system, it fails exactly the person most likely to be holding it.

What it changes, cheaply

I haven't rewritten everything. A few habits shifted, and none of them cost much.

I write error states as though the reader can't see the rest of the run. Not "step 3 failed" but what step 3 was attempting, what it got, and what it expected instead. One extra sentence now, an hour saved later.

I treat the clean error state as the audit trail I'm choosing to keep, not a nicety I add if time allows. In unattended work there is no other trail. The failure either left evidence or it didn't, and that's settled when I write the handler, not when the incident happens.

And I stopped tuning failure output for the moment it's watched. The version that reads well during a successful demo isn't the version that rescues you when it breaks alone at 2am. Different audiences, and the unattended one is the audience that actually needs the help.

Pick the harder reader

Compressed to a single line: useful right now and useful in three months are different specs, you usually only get to satisfy one, so write for the harder reader. Write the record a stranger would need, not the message you'd understand. You won't be in the room when it's read, and working when you're not there is the whole reason an error state exists.

I build WordPress plugins and write about AI tooling and security at https://raplsworks.com/.