Errors
Network reference: For the full cross-tool error code reference, see tools.fast/api/docs/errors.
Error envelope
All API errors return a JSON object with at least two fields (detail is null when no additional context applies):
{
"error": "machine.readable_code",
"detail": "Human-readable explanation."
}
Some errors include additional context fields (e.g. sourceFormat, supportedTargets).
400 Bad Request
Invalid request payload, parameters, or content type.
{
"error": "request.invalid_content_type",
"detail": "multipart/form-data required."
}{
"error": "convert.missing_target_format",
"detail": "targetFormat is required. Specify the desired output format (e.g., jpg, png, webp)."
}{
"error": "convert.unsupported_format_pair",
"detail": "Conversion from 'jpg' to 'mp3' is not supported.",
"sourceFormat": "jpg",
"targetFormat": "mp3",
"supportedTargets": ["avif", "ico", "pdf", "png", "webp"]
}{
"error": "convert.unsupported_source_format",
"detail": "No conversions available for source format 'xyz'.",
"sourceFormat": "xyz",
"supportedTargets": []
}{
"error": "request.empty_file",
"detail": "Uploaded file is empty."
}{
"error": "request.no_files",
"detail": "At least one file must be provided."
}401 Unauthorized
The API key is missing, invalid, or not allowed from the caller's IP.
{
"error": "api_key.invalid_or_ip_not_allowed",
"detail": "X-Fast-Api-Key was provided but is invalid for this request (or IP not allowlisted)."
}
This error intentionally does not distinguish between an invalid key and an IP not in the allowlist.
402 Payment Required
The caller's account does not have enough credits or has exceeded a usage limit.
{
"error": "entitlements.insufficient_credits",
"detail": "Insufficient credits. Required: 5, Available: 2"
}
403 Forbidden
The resource exists but the caller does not own it.
{
"error": "jobs.forbidden",
"detail": "You do not have access to this job."
}
404 Not Found
The requested job does not exist.
{
"error": "jobs.not_found",
"detail": null
}
The detail field may be null when no additional context applies.
409 Conflict
The request conflicts with the current state of the resource.
{
"error": "jobs.not_ready",
"detail": null
}{
"error": "jobs.not_cancellable",
"detail": "Cannot cancel completed, failed, or canceled jobs."
}{
"error": "jobs.not_deletable",
"detail": "Cannot delete a job that is still queued or running. Cancel it first."
}410 Gone
The job completed but its output artifacts have expired and been cleaned up. Output artifacts are retained for 1 hour after job completion, then automatically deleted. To clean up immediately after downloading, call DELETE /convert/job/{id}.
{
"error": "jobs.expired",
"detail": "Job artifacts were deleted on 2025-01-15 12:00:00Z after the retention period expired."
}
413 Payload Too Large
The uploaded file exceeds the per-converter or global size limit.
{
"error": "request.file_too_large",
"detail": "File exceeds the maximum allowed size.",
"megabytes": 50
}
429 Too Many Requests
The caller has been throttled. Check the Retry-After header.
{
"error": "rate_limited",
"detail": "Too many requests. Retry after 12 seconds."
}{
"error": "queue.limit_exceeded",
"detail": "Too many queued jobs. Wait for existing jobs to complete."
}Headers on 429 responses:
| Header | Description |
|---|---|
Retry-After | Seconds until you can retry |
Best practice: implement exponential backoff in your client, or honour the Retry-After value directly.
5xx Server Error
Server-side errors are rare but possible. Retry with exponential backoff (1s, 2s, 4s, 8s, max 30s). If errors persist, contact support@tools.fast.
Error codes reference
| Code | Status | Description |
|---|---|---|
request.invalid_content_type | 400 | Must use multipart/form-data |
request.no_files | 400 | No file attached |
request.empty_file | 400 | Uploaded file has zero bytes |
request.invalid_extension | 400 | File extension not accepted by converter |
request.multiple_files | 400 | Only one file per request |
request.file_too_large | 413 | File exceeds size limit |
convert.missing_target_format | 400 | targetFormat field not provided |
convert.invalid_options | 400 | Malformed options JSON |
convert.unsupported_source_format | 400 | No converter for the source format |
convert.unsupported_format_pair | 400 | Source format cannot convert to target |
convert.invalid_webhook | 400 | Webhook URL or secret failed validation |
api_key.invalid_or_ip_not_allowed | 401 | Bad API key or IP not in allowlist |
entitlements.insufficient_credits | 402 | Not enough credits |
jobs.forbidden | 403 | Job owned by another user |
jobs.not_found | 404 | Job ID does not exist |
jobs.not_ready | 409 | Download requested before job finishes |
jobs.not_cancellable | 409 | Job already completed/failed |
jobs.not_deletable | 409 | Cannot delete queued/running jobs — cancel first |
jobs.expired | 410 | Output artifacts cleaned up |
rate_limited | 429 | IP rate limit exceeded |
queue.limit_exceeded | 429 | Too many queued jobs |
estimate.unsupported_format_pair | 400 | Valid source format, but target not supported for estimation |
estimate.unsupported_source_format | 400 | Source format has no converters for estimation |
estimate.invalid_variant | 400 | Invalid cost variant specified |
schema.unsupported_format_pair | 400 | Valid source format, but target not supported for schema lookup |
schema.unsupported_source_format | 400 | Source format has no converters for schema lookup |
schema.converter_not_found | 400 | No converter found for the format pair |
server.internal_error | 500 | Unexpected server error — retry with exponential backoff |