English for Writing Clear Exit Codes and CLI Error Messages

Learn the English phrasing conventions for writing command-line tool error messages, help text, and exit code documentation that users can actually act on.

A command-line tool’s error messages are often the only English a user reads before they either fix the problem or give up and file an issue. Writing them well is a specific skill: terse enough to fit a terminal, but specific enough to be actionable. This guide covers the phrasing conventions for CLI error messages, help text, and exit code documentation.

Key Vocabulary

Exit code — the numeric status a program returns when it finishes, conventionally 0 for success and nonzero for various failure categories, used by scripts to detect success or failure programmatically. “We return exit code 2 specifically for configuration errors, distinct from exit code 1 for general runtime errors, so CI scripts can handle each case differently.”

Actionable error message — an error message that tells the user not just what went wrong, but what to do about it. “Instead of ‘invalid input,’ the actionable version says ‘invalid input: expected a number for —timeout, got “abc”. Try —timeout 30.’”

Usage line — the short summary shown when a CLI is invoked incorrectly, showing the expected syntax. “When required arguments are missing, we print the usage line: ‘Usage: mytool deploy —env <staging|production> [—dry-run]’.”

Verbose / debug flag — a flag that enables additional diagnostic output, referenced in error messages to tell users how to get more detail. “The error message ends with ‘Run with —verbose for the full stack trace,’ so users know how to get more information without us dumping it by default.”

Silent failure — a program exiting without any output or a nonzero exit code despite something going wrong, which is a usability bug because the user has no idea what happened. “This was a silent failure — the script exited 0 even though the upload failed, because we weren’t checking the response status. That’s now fixed, and it exits 1 with a clear message.”

Common Phrases

  • “Error: [specific problem]. [Specific suggested fix].”
  • “Expected [X], got [Y].”
  • “Run with —verbose for more detail.”
  • “Exit code [N]: [category of failure].”
  • “See [command] —help for usage.”

Example Sentences

Writing an actionable error instead of a vague one: “Error: could not connect to database at localhost:5432 (connection refused). Is the database running? Try ‘docker compose up db’ or check DATABASE_URL in your .env file.”

Documenting exit codes in a README or help output: “Exit codes: 0 = success, 1 = general error, 2 = invalid arguments, 3 = configuration file not found, 4 = network error. Scripts calling this tool can branch on these codes to handle failures differently.”

Writing a usage line that stays terse but complete: “Usage: backup-cli restore —snapshot [—target ] [—dry-run] Run ‘backup-cli restore —help’ for a full list of options.”

Fixing a silent failure and explaining the change in a changelog: “Fixed: the sync command previously exited with code 0 even when individual file uploads failed silently in the background. It now waits for all uploads to complete, reports failures explicitly, and exits with code 1 if any file failed to sync.”

Professional Tips

  • Structure error messages as problem + specific fix, not just problem — “expected a number, got ‘abc’. Try —timeout 30” is dramatically more useful than “invalid input.”
  • Document your exit code scheme somewhere findable (README, --help, man page) — scripts and CI pipelines depend on exit codes being stable and documented, not guessed at.
  • Never let a program exit successfully after a partial failure — if anything went wrong, the exit code and message both need to say so, even if the overall operation “mostly” succeeded.
  • Keep the first line of an error terse (it’s what appears in a scrollback buffer or a CI log summary), and put extended detail behind a --verbose flag rather than dumping everything by default.
  • Use consistent phrasing across all your tool’s error messages — if you use “Expected X, got Y” in one place, use the same structure everywhere, so users learn to parse your errors quickly.

Practice Exercise

  1. Rewrite a vague error message (“invalid config”) into an actionable one with a specific suggested fix.
  2. Write a short exit code table for a hypothetical CLI tool with four failure categories.
  3. Write a changelog entry describing a fix for a silent failure bug.