--- id: API-7 family: GR-API level: extended profiles: [storage-api] posture: normative-target added: "1.0" changed: "1.0" source: https://flowdrop.io/spec/rules/gr-api/api-7 specification: FlowDrop Workflow Specification 1.0-draft licence: CC BY 4.0 --- # API-7 — A generic failure is a last resort, never a design *GR-API (Part I) · level: extended · profiles: storage-api · added in 1.0* A catch-all failure answer is a reporting device. Where it stands in for a refusal the door could have named, it renders "this endpoint has never worked" indistinguishable from "the server hiccupped". ## The rule > **Normative.** This is the rule. > > 1. A failure an implementation cannot attribute to a specific cause is answered with a fixed generic message; the underlying failure's own message is logged and never reaches the response body. > > 2. A failure an implementation can classify must be answered as that classification (a client error as a client error, a refusal by the name the door has for it), and a generic server failure must never stand in for a refusal the door is able to name. ## What it means A generic failure message exists for the case an implementation genuinely cannot name: something broke, and nothing about the failure tells the door which refusal it should have been. That message is a last resort, not a convenience. Anything a door can attribute — a record that does not exist, a caller without the permission it needed, a body that failed the shared gate — must be answered as that specific thing, never folded into the same catch-all just because the code path happens to have one. The two failures read identically to a caller who only sees a status and a message that says nothing: "this has never worked" and "something broke just now" become indistinguishable. The underlying cause still belongs in the log; only the caller-facing body is generic, and only when nothing more specific was knowable. ## Example The same route answers a missing record and a denied one differently — neither collapses into the other's message. ```http title="A pipeline id nothing matches" verdict="404 refused" GET /api/flowdrop/pipeline/{pipeline}/logs {"success": false, "error": "Pipeline with ID 99999 does not exist."} ``` ```http title="The same route, denied to a caller with no permission on it" verdict="403 refused" GET /api/flowdrop/pipeline/{pipeline}/logs {"success": false, "error": "Access denied"} ``` Nothing this door cannot attribute to one of these is answered any other way: it gets the one fixed message, and the detail stays in the log. ## Related rules - Names: API-3, API-8 - Referenced by: API-1, API-3, API-8 --- Rule identifiers are permanent and are never renumbered. This specification carries no implementation status: each implementation publishes its own standing against these rules. Licensed CC BY 4.0.