Marble 2 beta
Errors and retries
Handle HTTP request failures separately from asynchronous operation failures.
- A non-2xx HTTP response means the API request did not return a successful result. A timed-out submission can still be uncertain.
- An accepted task can later finish with HTTP
200,done: true, and anerrorobject inside the operation.
HTTP errors
| Status | Typical meaning | What to do |
|---|---|---|
400 | Invalid argument or resource transition | Correct the request before retrying |
401 | Missing, unknown, expired, or revoked API key | Replace the credential |
403 | Missing scope or project mismatch | Fix scopes or resource ownership |
404 | Resource absent or task unavailable to this account | Verify the ID and beta access |
409 | ID collision or idempotency key reused with a different body | Reuse the original body or choose a new logical ID |
422 | JSON does not match the endpoint schema | Correct field names, types, and required values |
402 | Out of credits or a spend limit is reached | Add credits or adjust the limit, then resubmit |
429 | Submission or request rate exceeded | Honor Retry-After and reduce concurrency |
500 | Unexpected server failure | Retry safely; contact support if persistent |
503 | Required capacity temporarily unavailable | Retry with backoff and jitter |
Validation errors can contain a structured detail array. Other failures often
return a developer-readable detail string. Do not make program logic depend
on the wording; branch on status, operation state, and structured error codes.
HTTP 503 responses may include Retry-After. Wait at least that long before
retrying, and limit retries with backoff and jitter.
Machine-readable error codes
Rejected submissions put a stable string in the response's top-level code
field. Failed operations use a numeric error.code from google.rpc.Code and
put the more specific reason in a google.rpc.ErrorInfo entry inside
error.details. Branch on the string code or reason, not the message.
| Failure | Read from | Code or reason | Meaning |
|---|---|---|---|
| Rate limit | HTTP 429 response code | RATE_LIMIT_EXCEEDED | Too many requests were submitted in the current window. The request was not accepted; honor Retry-After. |
| Credits unavailable | HTTP 402 response code | CREDITS_UNAVAILABLE | The account cannot start paid work because billing does not currently allow new usage. Add credits before retrying. |
| Spend limit exhausted | HTTP 402 response code | SPEND_LIMIT_EXCEEDED | An account or project monthly spend limit was reached. Adjust the limit or wait for its reset before retrying. |
| Paid seat required | HTTP 402 response code | PAID_SEAT_REQUIRED | A member on a Free seat submitted subscription work in an account whose seats are paid, after its signup credits were spent. An account admin can assign a seat. Developer API keys are not affected. |
| Content blocked | Operation ErrorInfo.reason (error.code 3) | CONTENT_POLICY | The model declined the request's content under its content policy. The operation is terminal and a retry will likely be declined again; change the prompt or images. |
| Task execution failed | Operation ErrorInfo.reason (error.code 13) | EXECUTION_FAILED | The accepted task failed during execution. The operation is terminal; investigate before submitting a new task. |
| Task execution timeout | Operation ErrorInfo.reason (error.code 4) | EXECUTION_TIMEOUT | The accepted task exceeded its execution deadline. The operation is terminal; a retry is a new task submission. |
Numeric operation codes are intentionally broad. For example, code 4
(DEADLINE_EXCEEDED) can also accompany an expired task, so use the
ErrorInfo.reason to distinguish the failure. See Rate limits
and Billing for recovery guidance.
Operation failures
An accepted task may return a terminal operation such as:
Do not expect response on a failed terminal operation. For support, record
the operation ID, task name, HTTP status from the original submission, and
structured error metadata.
Retry without duplicate work
Create one Idempotency-Key before the first task submission. If the response
is lost or a transient failure occurs, retry the same body with that same key.
A successful replay returns the original operation.
Do not retry 400, 403, or 422 unchanged. For retryable reads and
submissions, use capped exponential backoff with jitter. Respect Retry-After
when present and stop after a bounded number of attempts or elapsed time.
Operation reads are safe to retry. Use a stable cancellation requestId when
retrying :cancel.
Avoid retry storms
Limit retries globally per project, not only per worker. After an outage, drain queued submissions gradually. Persist operation IDs before acknowledging jobs to your own queue so a restarted worker resumes polling instead of submitting again.