Outcomes
What every result means, what it returns, and whether to retry.
Every request produces exactly one outcome. There are 19 of them, grouped into 6 classes.
Branch on the class
X-Outcome is open and gains members as adapters land. X-Outcome-Class does not grow. Code written against the class keeps working when the vocabulary expands; code written against the outcome breaks on our schedule, not yours.
ok
Use it. Real content that passed validation.
| Outcome | HTTP | Failover | Billed | Meaning |
|---|---|---|---|---|
| OK | the target's | no | yes | Real content, passed validation |
blocked
Retry later. Every provider was blocked. Trying again immediately will be blocked again.
| Outcome | HTTP | Failover | Billed | Meaning |
|---|---|---|---|---|
| SOFT_BLOCK | 502 | yes | no | our detector fired on the body; a rule ID is attached |
| HARD_BLOCK | 502 | yes | no | Provider says blocked or banned |
target
Do not retry. The site itself answered. A 404 is still a 404 through another provider.
| Outcome | HTTP | Failover | Billed | Meaning |
|---|---|---|---|---|
| TARGET_NOT_FOUND | 404 | no | provider-dependent | Genuine 404, unless the provider has retry_404 semantics |
| TARGET_ERROR | 502 | once | no | Target site 5xx or DNS dead |
| TARGET_RATE_LIMITED | 429 | yes | no | Target rate-limited us (429); backs off per domain rather than retrying |
provider
Already retried. Proxlane failed over for you. Seeing this means the whole chain was exhausted.
| Outcome | HTTP | Failover | Billed | Meaning |
|---|---|---|---|---|
| PROVIDER_TIMEOUT | 504 | yes | no | Attempt exceeded its per-attempt budget |
| PROVIDER_ERROR | 502 | yes | no | Provider 5xx or infrastructure failure |
| RATE_LIMITED | 429 | yes | no | Provider 429 or concurrency cap |
| AUTH_FAILED | 502 | yes | no | Provider 401/403 on the key |
| PROVIDER_DRIFT | 502 | yes | no | Response failed its Zod schema |
| PROVIDER_BODY_OFFLOADED | 502 | yes | no | the provider stored the body out of band and returned a pointer we cannot follow |
client
Fix the request. Retrying an invalid request cannot help.
| Outcome | HTTP | Failover | Billed | Meaning |
|---|---|---|---|---|
| BAD_REQUEST | 400 | no | no | The client's request is malformed or impossible |
| TARGET_FORBIDDEN | 403 | no | no | Target rejected at our edge: private range, denylist, metadata address |
gateway
Retry later. Our side. Honour Retry-After when it is present.
| Outcome | HTTP | Failover | Billed | Meaning |
|---|---|---|---|---|
| INVALID_REQUEST | 500 | no | no | Our translation produced a provider 400 |
| NO_PROVIDER_AVAILABLE | 503 | no | no | No adapter matches the capability, or the chain is exhausted |
| RESPONSE_TOO_LARGE | 413 | no | no | Body exceeded the cap; see operations.md section 1 |
| BUDGET_EXCEEDED | 504 | no | no | Global deadline or cost budget hit |
| GATEWAY_BUSY | 429 | no | no | In-flight ceiling reached; the gateway shed this request rather than queue it |
Status codes
On success the target's own status passes through unchanged. That is the drop-in promise: code that already branches on a 404 keeps working. Everything else maps to a status of ours.
| 400 | BAD_REQUEST |
| 403 | TARGET_FORBIDDEN |
| 404 | TARGET_NOT_FOUND |
| 413 | RESPONSE_TOO_LARGE |
| 429 | TARGET_RATE_LIMITED, RATE_LIMITED, GATEWAY_BUSY |
| 500 | INVALID_REQUEST |
| 502 | SOFT_BLOCK, HARD_BLOCK, TARGET_ERROR, PROVIDER_ERROR, AUTH_FAILED, PROVIDER_DRIFT, PROVIDER_BODY_OFFLOADED |
| 503 | NO_PROVIDER_AVAILABLE |
| 504 | PROVIDER_TIMEOUT, BUDGET_EXCEEDED |