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:
{
"error": "machine.readable_code",
"detail": "Human-readable explanation."
}
Some errors include additional context fields.
400 Bad Request
Invalid request payload, parameters, or content type.
{
"error": "request.invalid_content_type",
"detail": "multipart/form-data required."
}{
"error": "request.empty_file",
"detail": "Uploaded file is empty."
}{
"error": "request.no_files",
"detail": "Exactly one file must be provided."
}{
"error": "request.invalid_extension",
"detail": "File extension '.mp3' is not accepted by this compressor."
}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.
{
"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
}
409 Conflict
The request conflicts with the current state of the resource.
{
"error": "jobs.not_ready",
"detail": "Job is still processing or waiting to start."
}{
"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 /compress/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-compressor 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 compressor |
request.multiple_files | 400 | Only one file per request |
request.file_too_large | 413 | File exceeds size limit |
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 |
compress.invalid_webhook | 400 | Webhook URL or secret failed validation |
compress.unsupported_format | 400 | File format not recognized by the universal compressor |
compress.{format}.validation.unsupported_format | 400 | File format not accepted by the format-specific compressor |
estimate.unsupported_format | 400 | No compressor found for the requested format |
schema.unsupported_format | 400 | No compressor found for the requested format |
compare.not_ready | 409 | Job not yet succeeded for comparison |
compare.expired | 410 | Output artifacts cleaned up |
compare.timeout | 504 | Preview generation timed out |
server.internal_error | 500 | Unexpected server error — retry with exponential backoff |