Error messages
An error message is read exactly when someone is stuck, frustrated, and
looking for the way out. "Invalid input" or "Something went wrong" adds
nothing to that situation. A message that earns its place names what
failed, shows the state that caused it, and points at the next action.
Method
- Name the specific thing. Not "file error" but "cannot read
config.yaml": the exact filename, key, field, or id. The reader should
not have to guess which of forty files the message means. Include the
identifier they can grep for.
- Show the offending state. Quote the actual value against the
expected shape: "port must be 1 to 65535, got 70000" or "expected 3
columns, row 12 has 5". The gap between got and expected is usually the
whole diagnosis.
- State the fix as an action. End with what to do: "set DATABASE_URL
in .env" or "run
migrate up first". A message that describes the
problem but not the remedy leaves the reader exactly where they started,
one search deeper.
- Write for the reader, keep internals in logs. A user sees "This
image is over 10 MB; compress it or choose another"; the stack trace,
error code, and request id go to the log. Correlate the two with an id
the user can quote, not by dumping the trace on their screen.
- Match severity to reality. Do not log an expected empty result as
ERROR, and do not whisper a data-loss risk at info. A log scanner
filtering on level trusts that you got this right; a miscolored line
hides the one that matters.
- State the fact, not blame or mood. Drop "Oops!", "Fatal!", and "You
entered an invalid value". Say what happened and what to do.
Blame-free, specific, actionable: the reader wants out, not an apology.
Signals
- Does the message name the exact field, file, or id, or only a vague
category?
- Could a first-time reader act on it without opening the source?
- Are got and expected both visible whenever a value is rejected?
Boundaries
Security-sensitive failures deliberately withhold detail: a login error
says "invalid credentials", never "no such user", and the diagnostic goes
to the log instead of the message. Internal panics on genuine bugs favor a
full stack trace over a polished sentence, because the audience there is
the developer, not the user.
1---2name: error-messages3description: Write error messages that name the specific thing, show the offending state, and state the fix as an action. Use when writing any thrown exception, log line, or user-facing failure text.4---56# Error messages78An error message is read exactly when someone is stuck, frustrated, and9looking for the way out. "Invalid input" or "Something went wrong" adds10nothing to that situation. A message that earns its place names what11failed, shows the state that caused it, and points at the next action.1213## Method14151. **Name the specific thing.** Not "file error" but "cannot read16 config.yaml": the exact filename, key, field, or id. The reader should17 not have to guess which of forty files the message means. Include the18 identifier they can grep for.192. **Show the offending state.** Quote the actual value against the20 expected shape: "port must be 1 to 65535, got 70000" or "expected 321 columns, row 12 has 5". The gap between got and expected is usually the22 whole diagnosis.233. **State the fix as an action.** End with what to do: "set DATABASE_URL24 in .env" or "run `migrate up` first". A message that describes the25 problem but not the remedy leaves the reader exactly where they started,26 one search deeper.274. **Write for the reader, keep internals in logs.** A user sees "This28 image is over 10 MB; compress it or choose another"; the stack trace,29 error code, and request id go to the log. Correlate the two with an id30 the user can quote, not by dumping the trace on their screen.315. **Match severity to reality.** Do not log an expected empty result as32 `ERROR`, and do not whisper a data-loss risk at `info`. A log scanner33 filtering on level trusts that you got this right; a miscolored line34 hides the one that matters.356. **State the fact, not blame or mood.** Drop "Oops!", "Fatal!", and "You36 entered an invalid value". Say what happened and what to do.37 Blame-free, specific, actionable: the reader wants out, not an apology.3839## Signals4041- Does the message name the exact field, file, or id, or only a vague42 category?43- Could a first-time reader act on it without opening the source?44- Are got and expected both visible whenever a value is rejected?4546## Boundaries4748Security-sensitive failures deliberately withhold detail: a login error49says "invalid credentials", never "no such user", and the diagnostic goes50to the log instead of the message. Internal panics on genuine bugs favor a51full stack trace over a polished sentence, because the audience there is52the developer, not the user.