The 200 OK error: when a success response carries a failure
Definition, why it is invisible by design, and a pre-registered experiment on the defaults · updated 2026-08-13 · no affiliate links on this page
HTTP 200 asserts that a message arrived and the server answered - nothing more. Whether the operation actually happened is stated inside the response body, and many real-world APIs report failures there while the status stays 200. Automation platforms evaluate step success on the HTTP status, so a success-wrapped failure enters your run history as a green checkmark: the transport layer worked, the business operation failed, and nothing anywhere disagrees with the word "success".
This failure class sits in a blind spot that is architectural, not accidental: the platform genuinely cannot know what a failure looks like inside an arbitrary API's response schema without being told. That makes it different from the failures on our reliability scoreboard - it is not the platform dropping your run, it is the platform faithfully recording a delivery whose content was a failure notice. The run log is telling the truth about the wrong layer.
Where it bites
- APIs that wrap errors in 200s. Payment processors returning declines as structured 200 responses, CRMs answering 200 with a validation-errors array, bulk endpoints that accept a batch and report per-record failures in the body. The workflow shows green; the payment declined, the contact was rejected, three records of ten were skipped.
- Schema drift. The destination API changes a field name or response shape; calls keep returning 200 while writes quietly stop landing where your downstream logic expects them. Nothing errors - the payload is simply wrong now.
- Soft limits. Some services throttle by accepting requests and deferring or discarding work rather than answering 429 - the polite cousin of the quota wall we measured on the reliability page, where accepted stopped meaning delivered.
The pre-registered experiment (EP3): measuring the defaults
Content about this failure class is plentiful; measurement of it is nonexistent - we have not found a single published test of what each platform's default configuration actually records when a destination answers 200 with an error body. So we are running one, and pre-registering the design here before results exist:
- Method: our receiving endpoint (the same self-hosted receiver behind all our benchmarks) gains a mode that answers experiment-tagged events with HTTP 200 and the body
{"ok": false, "error": "schema-drifted"}. We fire tagged events through the identical webhook→HTTP workflows we always run, platform settings at their defaults, and record what each platform's run history shows. - Expectation to falsify: all platforms record the step as successful (documented design on Zapier, Make and n8n). The measured part is confirming the defaults do this uniformly - and then measuring the cost of seeing: what a response assertion costs per run, per platform, in extra billable units.
- Status: running August 2026 on Zapier and self-hosted n8n (Make's paid window in our harness has closed; its documented behaviour is included for comparison). Results will be published on this page with raw logs, as with every experiment we run. These runs are excluded from the headline Silent Failure Rate - experiments never share a denominator with normal operation.
What to do about it today
Assert on the body, not the status: one added step that checks the response's success field (or the returned ID you expect) converts this silent class into a loud one, at the price of one extra billable step on per-task platforms. And because some failures produce a perfectly-shaped success body with no write behind it, keep the end-to-end net too: read-after-write on the records that matter, and daily counts-in versus counts-out - the same reconciliation discipline behind every number on our scoreboard.
FAQ
Can a webhook or API call fail even if it returns 200 OK?
Yes, and it is one of the most common silent-failure shapes in production automation. HTTP 200 only asserts that the request arrived and the server produced a response - the transport layer worked. Whether the operation succeeded is stated inside the response body, and plenty of APIs report failures there ({"success": false}, {"status": "error"}, a 200 with an empty result) while the HTTP status stays 200. Any system that equates 2xx with done - which is the default behaviour of automation platforms - records these failures as successes.
Does Zapier detect an error inside a 200 response?
Not by default, and this is documented design rather than a bug: Zapier (like Make and n8n) evaluates step success on the HTTP status, so a 200 response with an error payload marks the step successful and the run continues or completes green. Detecting it requires an explicit step you add yourself - a Filter on a response field in Zapier, a filter or router condition in Make, an IF node in n8n - which is also an extra billable step on per-task platforms. We are currently measuring exactly this behaviour under controlled conditions (see the experiment section on this page) and will publish per-platform results here.
How do I catch 200-OK errors in my workflows?
Two complementary layers. In-workflow: add a response assertion after the call - check the body's success field, or the presence of the ID you expect back, and route failures to an error path. This costs one extra step (billable on per-task platforms) and catches structured error bodies. End-to-end: read-after-write verification and daily count reconciliation - fetch what you just wrote and compare the fields that matter, and compare records-in against records-out on a schedule. The second layer is the only one that also catches the case where the API said success, returned 200, and still wrote nothing.
Related
The live Silent Failure Rate scoreboard · Silent failure vs rejected webhook · Uptime is not your failure rate · Webhook retry semantics, measured