Error Codes
All Tools.FAST APIs use a consistent error response format. The same error codes and structure apply across Convert.FAST, Compress.FAST, and every tool in the network.
Error envelope
Every error response returns a JSON object with at least two fields:
{
"error": "machine.readable_code",
"detail": "Human-readable explanation."
}
Some errors include additional context fields (e.g., sourceFormat, supportedTargets, megabytes).
HTTP status codes
400 Bad Request
Invalid request payload, parameters, or content type.
{
"error": "request.invalid_content_type",
"detail": "multipart/form-data required."
}
{
"error": "request.no_files",
"detail": "No files were provided in the request."
}
{
"error": "request.empty_file",
"detail": "Uploaded file is empty."
}
{
"error": "request.invalid_extension",
"detail": "File extension not accepted by converter."
}
{
"error": "request.invalid_parameter",
"detail": "Invalid value for parameter 'quality'."
}
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)."
}
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"
}
{
"error": "usage.daily_limit_exceeded",
"detail": "Daily usage limit exceeded. Used: 100/100"
}
403 Forbidden
The resource exists but the caller does not own it.
{
"error": "batch.forbidden",
"detail": "You do not have access to this batch."
}
404 Not Found
The requested job or batch does not exist.
{
"error": "jobs.not_found",
"detail": null
}
{
"error": "batch.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 jobs."
}
410 Gone
The job completed but its output artifacts have expired and been cleaned up.
{
"error": "jobs.expired",
"detail": "Job output has expired and is no longer available for download."
}
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."
}
{
"error": "queue.pool_saturated",
"detail": "Worker pool is at capacity. Try again shortly."
}
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.
Complete error codes reference
Request errors
| Code | Status | Description |
|---|---|---|
request.invalid_content_type |
400 | Must use multipart/form-data |
request.no_files |
400 | No file attached to the request |
request.empty_file |
400 | Uploaded file has zero bytes |
request.invalid_extension |
400 | File extension not accepted by the converter |
request.invalid_parameter |
400 | A request parameter has an invalid value |
request.multiple_files |
400 | Only one file per request is allowed |
request.image_too_large |
413 | Image dimensions exceed the maximum |
request.file_too_large |
413 | File exceeds the size limit for this converter/tier |
Authentication errors
| Code | Status | Description |
|---|---|---|
api_key.invalid_or_ip_not_allowed |
401 | API key is missing, invalid, or IP not in allowlist |
Entitlements errors
| Code | Status | Description |
|---|---|---|
entitlements.insufficient_credits |
402 | Not enough credits to process this job |
entitlements.queue_limit_exceeded |
402 | Maximum queued jobs reached for this tier |
entitlements.invalid_user |
402 | User account is not in a valid state |
entitlements.error |
500 | Internal entitlements service error |
Batch errors
| Code | Status | Description |
|---|---|---|
batch.not_found |
404 | Batch ID does not exist |
batch.forbidden |
403 | Batch belongs to another user |
batch.limit_exceeded |
429 | Too many active batches |
batch.zip_limit_exceeded |
400 | ZIP download exceeds size limit |
batch.output_limit_exceeded |
400 | Batch output exceeds limit |
batch.empty |
400 | Batch contains no jobs |
batch.expired |
410 | Batch artifacts have been cleaned up |
Job errors
| Code | Status | Description |
|---|---|---|
jobs.not_found |
404 | Job ID does not exist |
jobs.not_ready |
409 | Job is still processing; download not available yet |
jobs.expired |
410 | Job output has been cleaned up |
jobs.forbidden |
403 | Job belongs to another user |
jobs.timeout |
500 | Job exceeded the processing time limit |
jobs.not_deletable |
409 | Job cannot be deleted in its current state |
Queue errors
| Code | Status | Description |
|---|---|---|
queue.limit_exceeded |
429 | Too many queued jobs; wait for existing jobs to finish |
queue.pool_saturated |
429 | Worker pool is at capacity |
rate_limited |
429 | IP-level rate limit exceeded |
Usage errors
| Code | Status | Description |
|---|---|---|
usage.daily_limit_exceeded |
402 | Free/guest daily credit cap reached |
Tool-specific errors
Individual tools may define additional error codes under their own namespace. See each tool's API documentation for converter-specific errors:
- Convert.FAST errors --
convert.*codes for format-specific failures - Compress.FAST errors --
compress.*codes for compression failures
Handling errors in code
RESPONSE=$(curl -sS -w "\n%{http_code}" -X POST "https://api.tools.fast/convert" \
-H "X-Fast-Api-Key: $API_KEY" \
-F "file=@photo.heic" \
-F "targetFormat=jpg")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 400 ]; then
ERROR=$(echo "$BODY" | jq -r '.error')
DETAIL=$(echo "$BODY" | jq -r '.detail')
echo "Error $HTTP_CODE: [$ERROR] $DETAIL"
if [ "$HTTP_CODE" = "429" ]; then
echo "Rate limited. Retry after delay."
fi
exit 1
fi
JOB_ID=$(echo "$BODY" | jq -r '.id')
echo "Job submitted: $JOB_ID"
try {
$job = Invoke-RestMethod -Method Post "https://api.tools.fast/convert" `
-Headers @{ "X-Fast-Api-Key" = $env:API_KEY } `
-Form @{ file = Get-Item "photo.heic"; targetFormat = "jpg" }
Write-Host "Job submitted: $($job.id)"
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$body = $_.ErrorDetails.Message | ConvertFrom-Json
Write-Host "Error ${statusCode}: [$($body.error)] $($body.detail)"
if ($statusCode -eq 429) {
Write-Host "Rate limited. Retry after delay."
}
exit 1
}