Errors and Status Codes
How bem reports failures, how to retry safely, and how to handle partial successes
bem distinguishes two kinds of failure: request errors, returned synchronously when the API can't accept your call, and execution errors, which appear inside otherwise-successful workflow calls when one or more nodes fail. Both shapes are stable — your error-handling code only needs to know two things.
HTTP status codes
| Code | Meaning | When you'll see it |
|---|---|---|
200 OK | Success, body returned | Most reads; wait=true calls that completed |
202 Accepted | Accepted for async processing | Workflow calls without wait=true; eval queueing; collection item ingest |
204 No Content | Success, no body | Deletes |
207 Multi-Status | Partial success | Batch updates where some items succeeded and some failed (e.g. update-transformation) |
400 Bad Request | Invalid request | Schema violation, unsupported inputType, malformed outputSchema, contradictory filters |
401 Unauthorized | Missing or invalid API key | The x-api-key header is missing, malformed, or revoked |
404 Not Found | Resource doesn't exist | Wrong functionName/workflowName/callID, or you're targeting a different environment |
422 Unprocessable Entity | Request shape valid, semantics not | Body parses but violates a model constraint (e.g. workflow mainNodeName not in nodes) |
429 Too Many Requests | Rate limit exceeded | Back off and retry |
500 Internal Server Error | Server-side failure | Treat as retryable with backoff; if persistent, contact support with the response body |
Request-error shape
Every non-2xx response uses the same body schema:
{
"message": "human-readable description",
"code": 400,
"details": { "field": "outputSchema", "reason": "..." }
}| Field | Type | Notes |
|---|---|---|
message | string | Always present. Safe to surface to operators; not necessarily safe to surface to end users (may include resource names). |
code | integer | Optional. Mirrors the HTTP status when present. |
details | object | Optional, free-form. Carries field-level context for 400/422 responses; absent for most 500s. |
Treat the body as advisory and the HTTP status as authoritative. Don't switch on details.field strings — they're meant for humans, not parsers.
Execution errors inside workflow calls
When a workflow call partially or fully fails, the HTTP response is still 200 (or 202 if you didn't pass wait=true). The failure information lives inside the call object:
{
"call": {
"callID": "wc_abc123",
"status": "failed",
"outputs": [
{ "eventID": "ev_001", "eventType": "transform", "transformation": { ... } }
],
"errors": [
{
"eventID": "ev_002",
"functionCallID": "fc_abc",
"workflowNodeName": "invoice-extractor",
"errorMessage": "outputSchema constraint violation: field 'totalAmount' is required",
"createdAt": "2024-04-25T19:14:02Z"
}
],
"url": "/v3/calls/wc_abc123",
"traceUrl": "/v3/calls/wc_abc123/trace"
}
}Two things to note:
outputsanderrorsare not mutually exclusive. A workflow with three nodes can emit two terminal outputs and one error. Always check both.call.statusreflects the worst outcome. It'scompletedonly if every terminal node produced a non-error event. Any error event flips it tofailed. For per-node detail, fetch the trace attraceUrl.
Retry guidance
| Status | Retry? | How |
|---|---|---|
429 | Yes | Honour Retry-After if present, otherwise exponential backoff starting around 1s, capping near 10s. |
500/502/503/504 | Yes | Exponential backoff with jitter, max 5 attempts. |
408 | Yes | Same as 5xx. |
400/401/404/422 | No | The request itself needs to change; retrying as-is won't help. |
409 | Sometimes | When returned on a workflow create with a name collision, treat as terminal. |
Idempotency
bem uses callReferenceID (on workflow calls) as your deduplication key. Submitting the same callReferenceID for the same workflow within a short window returns the existing call instead of creating a new one — safe to retry network failures without producing duplicates.
For all other operations (function/workflow create + update), use the response's stable IDs (functionID, workflowID) to detect whether your retry succeeded after a network blip.
Common errors and what they mean
| Message fragment | What it means | Fix |
|---|---|---|
outputSchema constraint violation | Extracted JSON doesn't satisfy your outputSchema (usually a missing required field) | Surface as a workflow output error, not a 4xx — see call.errors[].errorMessage. Tighten upstream prompts or relax the requirement. |
unsupported inputType | The inputType you sent isn't in the supported list | See Supported file types. |
function name already exists | You called create with a name that's already in use in this environment | Either update the existing function or pick a new name. |
workflow mainNodeName must be one of nodes[].name | Topology mismatch | Fix the request body. |
BadRequestError: model state limit exceeded | The outputSchema is too large/complex for the underlying model | See Known limitations. Split the schema or reduce nesting. |
Observing errors after the fact
The /v3/errors endpoint lists terminal error events across calls and is the right place to power monitoring dashboards or alerts. Filter by workflowNames, functionNames, or callIDs to scope to a specific surface.