Error Responses
All API errors return a consistent JSON envelope so your code can handle them uniformly regardless of which endpoint produced the error.
Error Shape
Every error response uses the same structure:
{
"error": {
"code": "error_code_here",
"message": "Human-readable description of what went wrong.",
"request_id": "01JAXBKM3N4P5Q6R7S8T9UVWXY"
}
}
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code (see table below) |
message | string | Human-readable description, suitable for logging but not for end users |
request_id | string | Unique ULID for tracing this request |
The request_id is generated by the authentication middleware for every /v1/* request. Include it when contacting support.
Error Code Reference
| HTTP Status | Code | Description | Endpoint(s) |
|---|---|---|---|
| 400 | invalid_request | Request validation failed — missing required fields or out-of-range values | POST /v1/jobs, POST /v1/workers/ack |
| 400 | invalid_cron_expression | Cron expression could not be parsed by the Cronos library | PUT /v1/recurring/{id} |
| 400 | invalid_timezone | The timezone string is not a valid IANA timezone identifier | PUT /v1/recurring/{id} |
| 401 | unauthorized | Missing, malformed, or invalid API key | All /v1/* endpoints |
| 404 | job_not_found | Job ID does not exist or belongs to a different project | GET /v1/jobs/{id}, POST cancel, POST retry, POST ack, POST heartbeat |
| 404 | recurring_job_not_found | Recurring job ID does not exist for this project | DELETE /v1/recurring/{id} |
| 409 | idempotency_conflict | A job with the same idempotency_key already exists | POST /v1/jobs |
| 409 | invalid_state | The operation is not valid for the job's current state | POST cancel, POST retry, POST ack, POST heartbeat |
| 409 | worker_mismatch | The worker_id does not match the worker that claimed the job | POST /v1/workers/ack, POST /v1/workers/heartbeat |
| 409 | parent_terminal | Parent job is in a terminal state (cancelled or dead_letter) | POST /v1/jobs (continuations) |
| 409 | recurring_job_type_conflict | A recurring job with the same job_type already exists under a different ID | PUT /v1/recurring/{id} |
| 422 | parent_not_found | The parent_job_id does not reference an existing job | POST /v1/jobs (continuations) |
| 429 | rate_limit_exceeded | Hourly request limit exhausted for this project | All /v1/* endpoints |
| 500 | internal_error | Unhandled server error — safe to retry with backoff | All endpoints |
Validation Errors (400)
Validation is performed by FluentValidation before the request reaches the endpoint handler. When validation fails, the API returns a 400 with code: "invalid_request" and the message contains the first validation failure.
Create Job Validation
| Field | Rule | Error message |
|---|---|---|
job_type | Required, non-empty | "job_type is required." |
job_type | Max 500 characters | "job_type must not exceed 500 characters." |
payload | Required, non-null JSON | "payload is required." |
max_attempts | 1–100 (when provided) | "max_attempts must be between 1 and 100." |
timeout_seconds | 1–86,400 (when provided) | "timeout_seconds must be between 1 and 86400." |
queue | Max 100 characters (when provided) | "queue must not exceed 100 characters." |
idempotency_key | Max 200 characters (when provided) | "idempotency_key must not exceed 200 characters." |
parent_job_id | Max 36 characters (when provided) | "parent_job_id must not exceed 36 characters." |
Ack Request Validation
| Field | Rule | Error message |
|---|---|---|
job_id | Required, non-empty | "job_id is required." |
worker_id | Required, non-empty | "worker_id is required." |
status | Must be "succeeded" or "failed" | "status must be 'succeeded' or 'failed'." |
Example validation error
{
"error": {
"code": "invalid_request",
"message": "job_type is required.",
"request_id": "01JAXBKM3N4P5Q6R7S8T9UVWXY"
}
}
Handling Errors in Code
When using the Zeridion.Flare SDK, API errors are mapped to typed exceptions:
try
{
await jobClient.EnqueueAsync<SendWelcomeEmail>(new { Email = "user@example.com" });
}
catch (FlareAuthenticationException)
{
// 401 — invalid or expired API key
}
catch (FlareRateLimitException ex)
{
// 429 — wait until rate limit resets
if (ex.ResetAt.HasValue)
{
var delay = ex.ResetAt.Value - DateTimeOffset.UtcNow;
if (delay > TimeSpan.Zero)
await Task.Delay(delay);
}
}
catch (FlareConflictException)
{
// 409 — idempotency conflict, state transition error, etc.
}
catch (FlareNotFoundException)
{
// 404 — job or recurring job not found
}
catch (FlareApiException ex)
{
// Base class for all API errors
Console.WriteLine($"Error {ex.StatusCode}: {ex.ErrorCode} — {ex.Message}");
}
See the SDK Exceptions reference for the full exception hierarchy.