Errors
The Transcodely API uses Connect-RPC error codes with structured error details. Every error response includes a machine-readable code, a human-readable message, and — for validation errors — field-level details that pinpoint exactly what went wrong.
Error Response Format
All error responses follow this structure:
{
"code": "invalid_argument",
"message": "Request validation failed",
"details": [
{
"type": "transcodely.v1.ErrorDetails",
"value": {
"code": "validation_error",
"message": "Request validation failed",
"field_violations": [
{
"field": "outputs[0].video[0].codec",
"description": "codec is required"
},
{
"field": "input_url",
"description": "must match pattern: ^(gs|s3|https?)://.*$"
}
]
}
}
]
}Key design decisions:
- All validation errors are returned at once — the API does not stop at the first error
- Field paths include array indices — e.g.,
outputs[0].video[0].h264.crf - Errors are machine-readable — the
codefield is always a stable, lowercase string
Connect-RPC Error Codes
| Code | HTTP Status | Description |
|---|---|---|
invalid_argument | 400 | Request validation failed (bad input) |
not_found | 404 | Resource does not exist |
already_exists | 409 | Resource already exists (e.g., duplicate slug) |
permission_denied | 403 | Authenticated but not authorized for this action |
unauthenticated | 401 | Missing or invalid API key |
failed_precondition | 400 | Request cannot be fulfilled in current state |
resource_exhausted | 429 | Rate limit exceeded |
internal | 500 | Unexpected server error |
unavailable | 503 | Service temporarily unavailable |
deadline_exceeded | 504 | Request timed out |
unimplemented | 501 | Endpoint not yet implemented |
ErrorDetails
The details array contains one or more ErrorDetails objects with additional context:
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code (e.g., validation_error, parameter_out_of_range) |
message | string | Human-readable error description |
field_violations | FieldViolation[] | List of field-level errors (for validation failures) |
FieldViolation
Each field violation points to a specific field in the request:
| Field | Type | Description |
|---|---|---|
field | string | Dot-notation path to the invalid field |
description | string | What is wrong with the field |
Field paths use dot notation with array indices:
input_url— top-level fieldoutputs[0].type— first output’s type fieldoutputs[0].video[0].h264.crf— nested codec optionmetadata.my_key— metadata entry
Common Error Scenarios
Invalid API Key
{
"code": "unauthenticated",
"message": "Invalid or missing API key"
}Cause: The Authorization header is missing, the key is malformed, the key has been revoked, or the key has expired.
Solution: Check that you are passing a valid API key as Bearer {{API_KEY}} in the Authorization header.
Resource Not Found
{
"code": "not_found",
"message": "Job not found: job_nonexistent123"
}Cause: The resource ID does not exist, or it belongs to a different app.
Solution: Verify the resource ID and ensure you are using the correct API key (keys are scoped to an app).
Validation Error
{
"code": "invalid_argument",
"message": "Request validation failed",
"details": [
{
"type": "transcodely.v1.ErrorDetails",
"value": {
"code": "validation_error",
"message": "Request validation failed",
"field_violations": [
{
"field": "outputs[0].video[0].h264.crf",
"description": "CRF must be between 15 and 35"
}
]
}
}
]
}Cause: One or more request fields failed validation.
Solution: Read each field_violation to identify and fix the invalid fields. All violations are returned at once so you can fix them in a single pass.
Organization Suspended
{
"code": "permission_denied",
"message": "Organization is suspended"
}Cause: The organization associated with the API key is suspended (usually due to a billing issue).
Solution: Contact support or resolve the billing issue to reactivate the organization.
Duplicate Resource
{
"code": "already_exists",
"message": "Preset with slug 'web_720p_fast' already exists"
}Cause: Attempting to create a resource with a slug or identifier that is already in use.
Solution: Use a different slug, or retrieve the existing resource.
State Conflict
{
"code": "failed_precondition",
"message": "Job is not in a cancelable state: completed"
}Cause: The requested operation is not valid for the resource’s current state (e.g., canceling a completed job, confirming a job that is not awaiting confirmation).
Solution: Check the resource’s current status before making state-transition requests.
Error Handling Best Practices
- Always check the
codefield for programmatic error handling — do not parse themessagestring. - Handle all validation errors at once — the API returns every field violation in a single response.
- Retry on
unavailableandresource_exhausted— use exponential backoff with jitter. - Do not retry on
invalid_argumentornot_found— these indicate a problem with your request. - Log the full error response — including
detailsandfield_violations— for debugging.
Error Handling Example
import { ConnectError, Code } from '@connectrpc/connect';
try {
const job = await client.create(request);
} catch (err) {
if (err instanceof ConnectError) {
switch (err.code) {
case Code.InvalidArgument:
// Parse field violations from err.details
console.error('Validation failed:', err.message);
break;
case Code.NotFound:
console.error('Resource not found');
break;
case Code.Unauthenticated:
// Redirect to login or refresh credentials
break;
case Code.Unavailable:
// Retry with exponential backoff
break;
default:
console.error('Unexpected error:', err.code, err.message);
}
}
}