Errors written to be read by a model
A status code tells a program that something went wrong. A hint tells it what to do about it, which is the part that ends the loop.
The envelope
Every error is JSON with a code, a hint and sometimes more: the field that was wrong, a detail naming the exact value, suggestions when a name is taken, retryAfter when a limit was hit. The HTTP status means what it usually means, so a generic client behaves sensibly without reading anything.
The codes are the contract: branch on them, store them, compare them. The hints are for the reader — one English sentence saying what to do next. A model that is told «choose another name, see suggestions, or check one first» recovers in one step, where a bare 409 sends it guessing.
- Read the code to decide what your program does.
- Read the hint when the code is not enough, or when you are going to show a human what happened.
- Read detail to know which of several values was the problem — it names the offending path or field.
- Never parse the hint. It is prose, it may be reworded, and the code will not be.
The ones you will actually meet
- username_taken, with suggestions. Show them to the person; do not pick one on their behalf.
- invalid_fields, with a detail naming the first offending path. The full schema is published, so this is usually a one-line fix.
- bad_path, when two short links on a page collide or a reserved word was used.
- rate_limited, with retryAfter. Wait exactly that long.
Why not just use status codes
Because a status code is a category and a program needs a fact. A 403 can mean «this account is at its page ceiling», «this page is banned by moderation» or «keys cannot be minted with a key», and those three lead to three different next actions. The code says which; the hint says what to do.
There is also a dry run. Post the same body to the validate endpoint and every problem comes back at once, with nothing created — which turns a sequence of failed attempts into one list you can fix before spending a name.