Every refusal carries a stable machine-readable code
A client has to be able to tell one refusal from another without reading English. Codes are the contract; the message is for a person.
The rule
- Every refusal an API door emits carries a stable, machine-readable
error_codealongside the human-readableerrorstring. - Message text is never contract: a client must not classify a refusal by matching its message, and an implementation must not treat wording as load-bearing.
- A code has one published definition that a client and a test can both name by it, and once published a code's meaning never changes and the code is never reused.
What it means
The human-readable message on a refusal is for a person; it is never what a
client is allowed to match against. A client that classifies a refusal by
matching a substring of the message is reading a field that can be reworded
at will, and a rewording that drops the substring it depended on
reclassifies the refusal without anything failing anywhere. The error_code
exists so a client never has to do that.
A code, once published, keeps its meaning forever and is never reused for something else — the same status code can and does cover more than one reason, and the code is what tells those reasons apart.
Example
Two refusals on sibling doors share a status and nothing else.
POST /flowdrop/api/pipelines/{pipeline}/resume
{}POST /flowdrop/api/pipelines/{pipeline}/cancel
{}Both are 409s; the code is what a client reads to tell one from the other.
Why
Recorded under OPEN-18.