Why does Go style require errors.New strings to start lowercase and end without punctuation?
answer
- your string rarely prints alone
- callers glue clauses together with colons
- it lands mid-sentence, not at the start
- no period, and no newline either
- initialisms are the exception
basics
~10 sAn error string is rarely printed alone. Callers wrap it, so it lands in the middle of a longer message. Lowercase text with no trailing period or newline concatenates cleanly into one readable line.
solid answer
~50 sIn Go an error is a value that travels upward, and almost every layer that touches it adds a prefix with `fmt.Errorf` before anything is printed. So the string you pass to `errors.New` is not a sentence of its own — it is a clause that will end up in the middle of `sync origin: fetch refs: no remote configured`. A capital letter there reads as a sentence restarting, and a trailing period or newline lands mid-line. That is the whole rationale: lowercase, no terminal punctuation, no `\n`. The exceptions are words that are capitalised everywhere — proper nouns and initialisms — which is why `io.EOF`'s message is literally `EOF`. Nothing in the standard toolchain enforces this; it is a convention carried by review, and the standard library follows it consistently (`fs.ErrNotExist` is `file does not exist`, `sql.ErrNoRows` is `sql: no rows in result set`).
code
go · 4 linesvar errNoRemote = errors.New("no remote configured")
// avoid: the capital and the period land mid-line once a caller wraps this
var errBadStyle = errors.New("No remote configured.")go deeper
Be ready to state the rule and the reason in one breath: lowercase, no trailing period, no newline, because a caller will wrap the text and it ends up mid-line. Quoting a standard-library message as evidence lands well.
Explain the composition mechanic — each layer prepends a clause and joins with a colon — and name the exceptions for proper nouns and initialisms. Knowing that nothing in the toolchain checks it separates you from someone repeating a lint rule.
Show how you hold the convention across a team: what you flag in review, why inconsistent capitalisation makes the same failure render differently depending on which layer caught it, and how that hurts anyone searching a pasted message.
Frame error prose as a user-visible surface with a house style, alongside log and CLI output conventions, and be able to argue why enforcing it by review is proportionate rather than adding tooling for it.
## The rule An error string in Go — the argument to `errors.New`, or the format string of `fmt.Errorf` — is written in lowercase, with no full stop, exclamation mark, or trailing newline. `errors.New("no remote configured")`, not `errors.New("No remote configured.")`. ## Why: the string is a clause, not a sentence Go returns failures as values. A failure that starts deep in a call stack is normally decorated on the way out: the function that dialled a host adds `dial 10.0.0.5:9418`, the one fetching refs adds `fetch refs`, the command adds `sync origin`. By the time anything is rendered, the original text sits at the end of a chain: ``` sync origin: fetch refs: dial 10.0.0.5:9418: connection refused ``` That single line is the product. Every piece of it is a clause joined by `: `. If the innermost clause had been written as a standalone sentence — `Connection refused.` — the rendered line becomes `sync origin: fetch refs: dial 10.0.0.5:9418: Connection refused.`, with a capital appearing mid-line and a full stop that stops nothing, because a further layer may still append to it. The convention exists so that authors of the inner layer, who cannot know how deep they will end up, write text that composes correctly at every depth. The same argument covers the newline. If a message ends with a line break, the caller who wraps it gets a message that spans two lines, and the caller who logs it gets a blank line. Formatting the output — where the line ends, whether it is indented, whether it goes to a terminal or a structured log — belongs to whoever finally prints the error, not to whoever created it. An error string should be a single line of text and nothing else. ## The exceptions The rule is about the *style* of the first character, not about forcing words into lowercase that are never lowercase. Capitalise when the first word is a proper noun or an initialism: `HTTP`, `JSON`, `TLS`, `Unicode`, or an exported identifier you are naming. The canonical example is in the standard library: `io.EOF` carries the message `EOF`, because that is how the term is spelled. Similarly, an error that names an exported function keeps that function's real spelling. A related habit, also visible in the standard library, is a package-name prefix on package-level sentinel errors: `sql.ErrNoRows` renders as `sql: no rows in result set`. That prefix is lowercase because the package name is lowercase, and it makes an otherwise generic phrase attributable when it turns up inside a long chain. ## What the rendered text is for Two audiences read it. The first is a user staring at a terminal, who needs a line that reads left-to-right from the broadest operation to the specific cause. The second is an engineer triaging a bug report, who takes the pasted line and searches for a distinctive fragment of it. Both are served by short, uniform, punctuation-free clauses; both are hurt by sentence-shaped fragments that vary in capitalisation, because the same underlying failure then renders differently depending on which layer happened to catch it. ## What does not enforce it `gofmt` reformats code, not string literals; the compiler does not care; the vet checks shipped with `go test` do not inspect error prose. This is a convention held up by code review and by consistency with the standard library. That makes it a good interview question: a candidate who knows it has read Go code written by other people, not just written their own. ## Writing one well A useful shape for the inner-most message is *what could not be established*, stated as a noun phrase or a short clause: `no remote configured`, `file does not exist`, `unexpected EOF`, `invalid port number`. Avoid re-stating that something failed — the fact that the value is an `error` already says so. Avoid the word `error` inside the text, which produces `error: error: ...` once printed by a top-level handler that adds its own prefix. Avoid embedding a newline or tab even when the message contains a value you did not write; quote such values instead so they cannot break the line. ## In one line Lowercase and unpunctuated because the string is a fragment of a message somebody else will finish, and no `\n` because the formatting decision is the printer's, not yours.
- When is capitalising the first word of a Go error string correct?When the word is capitalised everywhere else: a proper noun, an initialism such as HTTP or JSON, or an exported identifier you are naming. The standard library's `io.EOF` carries the message `EOF` for exactly that reason. The rule bans sentence-style capitalisation, not correct spelling.
- Why must an error string not end with a newline?Because the code that finally prints it decides the formatting. A trailing newline gives a blank line in a log, splits the message in two once a caller wraps it, and breaks tools that assume one record per line. Return one line of text and let the printer add the break.
- Does anything in the go toolchain flag a capitalised error string?No. `gofmt` does not touch string literals, the compiler does not care, and the vet checks that `go test` runs do not read error prose. It is a review convention, reinforced by the standard library following it everywhere.
saying these in an interview costs you the question
- Thinks gofmt or the compiler enforces the convention
- Ends every error string with a full stop because it is a sentence
- Capitalises error strings the way log lines are capitalised
- Appends a newline so the message prints on its own line
- Calls the rule arbitrary and ignores that callers wrap the text
- Believes the exception for initialisms means any exported error may be capitalised