Skip to content

Attach a hint

A message says what went wrong. A hint says what to do about it.

return errors.WithHint(
    errors.New("configuration uses auth.env, which is no longer read"),
    "Move the value to auth.value, or set the environment variable directly.",
)

Why they are separate

The two have different audiences and different lifetimes. A message is what gets logged, matched and wrapped as the error travels. A hint is what a CLI prints to a human at the edge, once, when it decides to give up.

Keeping them apart means a library can offer guidance without a caller being forced to render it, and a caller can render guidance without parsing it back out of a sentence.

fmt.Println(err)                 // configuration uses auth.env, which is no longer read
errors.Hints(err)                // [Move the value to auth.value, or set …]

Formatting

errors.WithHintf(err, "Move %s to %s.", oldKey, newKey)

More than one

Hints accumulate as an error travels, outermost first, and identical ones collapse:

inner := errors.WithHint(errors.New("root"), "check the token")
outer := errors.WithHint(errors.Wrap(inner, "loading"), "run `mytool init`")

errors.Hints(outer)        // [run `mytool init`, check the token]
errors.FlattenHints(outer) // "run `mytool init`\n--\ncheck the token"

Outermost first is deliberate: the layer closest to the user knows most about what they were trying to do.

Hints, details and attributes

Use For Audience
WithHint what to do about it the user
WithDetail context that is prose an operator reading verbose output
WithAttrs context that is data a query over logs or traces

See Hints, details and attributes for where the line sits.

Writing a good one

State the action, not the diagnosis. The message already has the diagnosis.

// weak — restates the problem
"The configuration key auth.env is not read."

// better — tells them what to change
"Move the value to auth.value, or set GITEA_TOKEN directly."

Name the concrete thing where you can: the key, the file, the command. A hint that could apply to any error is not doing more than the message.