Skip to content

Errors

The Layer REST API uses conventional HTTP status codes and returns a consistent, machine-readable error body following RFC 7807 Problem Details.

Errors are returned with the application/problem+json content type and this shape:

{
"type": "https://api.layer.ai/errors/WORKSPACE_NOT_FOUND",
"title": "Workspace not found",
"status": 404,
"detail": "Workspace 2489e9ad-… doesn't exist or you're not a member.",
"error_code": "WORKSPACE_NOT_FOUND"
}
  • error_code: the machine-readable error code. Branch on this, not on the human-readable title or detail.
  • type: a stable URI ending in the same code.
  • status: mirrors the HTTP status.
  • detail: a human-readable explanation. For 4xx errors this is specific; for 5xx errors it’s scrubbed to a generic message.
Code Status Meaning
UNAUTHENTICATED 401 Missing or invalid bearer token. See Authentication.
FORBIDDEN 403 The authenticated user lacks permission for this action or workspace.
INSUFFICIENT_BALANCE 402 Not enough Creative Units. See Creative Units & billing.
RATE_LIMITED 429 Too many requests. See Rate limits.
WORKSPACE_NOT_FOUND 404 Workspace doesn’t exist or you’re not a member.
MODEL_NOT_FOUND 404 Model not found or not available in this workspace.
WORKFLOW_NOT_FOUND 404 Workflow not found or not linked to this workspace.
INFERENCE_NOT_FOUND 404 Inference (forge) run doesn’t exist.
RUN_NOT_FOUND 404 Workflow run doesn’t exist.
INVALID_INPUTS 422 Malformed parameters, UUIDs, or an invalid pagination cursor.
UPLOAD_FAILED 502 A file could not be downloaded or stored.
INTERNAL_ERROR 500 An unexpected server error. Retry later; contact support if it persists.

Generation is asynchronous, and not every failure surfaces as an HTTP error. In particular, your Creative Unit balance is not checked when you submit a run: an underfunded run is accepted with 202 and later reaches a terminal failed/failure state carrying error_code: INSUFFICIENT_BALANCE.

Guardrails and provider content policies judge a generation after it is accepted, so a refusal never comes back as a 4xx. The run fails with one of these error_code values, and carries a refusal object that says why:

Code Meaning
INPUT_GUARDRAIL_VIOLATION A guardrail your workspace or project set blocked the request. Nothing was sent to the provider.
CONTENT_POLICY_VIOLATION The model provider refused the request under its content policy.
PROMPT_INTELLECTUAL_PROPERTY The model provider refused the request because it asked for protected intellectual property.
NO_MEDIA_GENERATED The provider returned no output and gave no reason. This is usually a silent refusal of the prompt.
{
"inference_id": "6f1c…",
"status": "failed",
"error": "This request was blocked by your workspace's “No Nintendo IP” guardrail. The prompt names Mario.",
"error_code": "INPUT_GUARDRAIL_VIOLATION",
"refusal": {
"inference_id": "6f1c…",
"code": "INPUT_GUARDRAIL_VIOLATION",
"guardrails": [
{
"guardrail_id": "0b6e…",
"name": "No Nintendo IP",
"category": "custom",
"reason": "The prompt names Mario."
}
]
}
}
  • guardrails: for INPUT_GUARDRAIL_VIOLATION, every guardrail that blocked the request, with its id, its name, the reason it gave, and its category: copyright_infringement, ip_trademark_infringement or artist_style_mimicry for the guardrails Layer ships, custom for a rule your workspace wrote. Empty for every other code.

refusal is null on every other outcome. A workflow run that a refused generation stopped fails with BlueprintInvalidRuntimeValueError and lists every refused generation in refusals, oldest first, in the same shape. Webhook deliveries carry the same fields, since their data is the matching GET body.

Resubmitting the same inputs is refused the same way. Change the prompt or the reference images, or ask a workspace admin about the guardrail it names.

  • Retry 429 after the Retry-After interval, and 5xx with exponential backoff.
  • Do not blindly retry 4xx errors other than 429. Fix the request first.
  • A retry of an execute request that actually succeeded server-side creates a duplicate run unless you sent an idempotency key with it. Send one on every submit, or prefer polling an existing run over re-submitting.