Error codes
Every error code GarmentVerse can return, why, and how to handle it.
#Error envelope
Every non-2xx response is a typed JSON envelope:
{
"error": {
"code": "bad_request",
"message": "Empty file",
"detail": { "field": "file" }
}
}The HTTP status maps 1:1 to code. Always log the X-Request-ID response header — it's what we'll need if you write to support.
#All error codes
| Code | HTTP | Cause | Retry? |
|---|---|---|---|
| bad_request | 400 | Malformed JSON, missing required field, unsupported MIME type, etc. | no |
| unauthorized | 401 | Missing or invalid API key, or revoked key. | no |
| forbidden | 403 | Authenticated but action not allowed — most often consent_token: false. | no |
| not_found | 404 | file_id, job_id, or key_id not found in this workspace. | no |
| conflict | 409 | Idempotency key collision in an unusual state. | yes (idempotent) |
| validation_error | 422 | Body parsed but failed schema validation. detail lists each field. | no |
| rate_limited | 429 | Too many requests in a short window. | yes (with backoff) |
| quota_exhausted | 402 | Workspace credit balance is zero or below the request cost. | after top-up |
| provider_unavailable | 503 | All eligible providers for this request are unhealthy or unconfigured. | yes (with backoff) |
| internal_error | 500 | Unexpected server error. | yes (once) |
#Recommended retry policy
For retryable codes, use exponential backoff with jitter and cap at 3 attempts. Always retry with the same idempotency_key.
async function withRetry<T>(fn: () => Promise<T>, max = 3): Promise<T> {
for (let i = 1; i <= max; i++) {
try {
return await fn();
} catch (e: any) {
const code = e?.code as string | undefined;
const retryable = ["rate_limited", "provider_unavailable", "internal_error", "conflict"];
if (i === max || !retryable.includes(code ?? "")) throw e;
const ms = Math.min(8000, 500 * 2 ** (i - 1)) * (1 + Math.random() * 0.25);
await new Promise((r) => setTimeout(r, ms));
}
}
throw new Error("unreachable");
}#Job failures vs API errors
A try-on job that succeeds at the API layer (returns 202) can still fail later in the pipeline. Read GET /v1/jobs/{id} until status: succeeded | failed | cancelled; the error field on a failed job tells you why. Failed jobs are not billed.
Still stuck?
Email support@garmentverse.dev with your request_id and we'll dig in. For incidents, check the status indicator in the footer or the API reference page.