Problem details
For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append.mdto anykestra.io/docs/*URL for plain Markdown.
Every error the Kestra API returns is an RFC 9457 problem details document, served as application/problem+json. Two things are outside that: the Model Context Protocol transport under /mcp/, whose errors are JSON-RPC 2.0 envelopes, and the few routes that answer with an error body of their own, which is left as the route sent it.
A request that tries to create a flow whose id is taken returns:
{ "type": "https://kestra.io/docs/api-reference/problems/entity-already-exists", "title": "Entity already exists", "status": 409, "detail": "A flow with id 'my-flow' already exists in namespace 'company.team'.", "instance": "/api/v1/main/flows"}Document members
| Member | Always present | Description |
|---|---|---|
type | yes | Stable identifier of the kind of problem, as a URI that resolves to its page below. This is the only member to branch on. |
title | yes | Short summary of the kind of problem. Identical for every occurrence of a given type, and never parameterised. |
status | yes | The HTTP status code, repeated in the body for convenience. |
detail | yes | Explanation of this particular occurrence, written for a human. |
instance | yes | Path of the request that produced the problem. |
errors | no | Field-level or per-item errors, when several problems are reported at once. |
traceId | no | Correlation identifier for the matching server-side log entry. Present on server errors only. |
Absent members are omitted rather than sent as null.
Branch on type, never on text
type is a permanent, published URI. Once a type ships it is never renamed or repurposed, so it is safe to switch on:
if problem["type"].endswith("/entity-already-exists"): ...title is stable for a given type and never contains values from the request, which makes it safe to display verbatim or to use as a key for your own translations.
detail is the opposite. It is written for whoever reads the error, it embeds ids and paths from the request, and its wording changes between releases. Never parse it, and never make behavior depend on it.
status and type agree, with one exception: an endpoint that explicitly raises an unusual status reports that status as sent, rather than having it normalised to the type’s own. Read status from the response.
Field-level errors
When a request fails for more than one reason, each reason is an entry in errors:
{ "type": "https://kestra.io/docs/api-reference/problems/validation-failed", "title": "Validation failed", "status": 422, "detail": "Validation failed", "instance": "/api/v1/main/flows", "errors": [ { "detail": "must not be null", "pointer": "/tasks/0/type", "path": "tasks[my-task].type" } ]}| Member | Description |
|---|---|
detail | What is wrong with this field or item. |
pointer | RFC 6901 JSON Pointer locating the field in the submitted document. |
path | Friendlier locator that names tasks and inputs by their id. Not a JSON Pointer. |
type | The item’s own problem type, on bulk endpoints where it differs per item. |
Both locators are carried because neither is enough on its own: pointer is valid for machine use, and path is what to show a user. Entries are ordered deterministically, so the same request always produces the same document.
Server errors
A 5xx problem never echoes the underlying exception message. Its detail is always the same fixed sentence, and it carries a traceId that ties the response to the server log entry holding the real cause:
{ "type": "https://kestra.io/docs/api-reference/problems/internal-error", "title": "Internal server error", "status": 500, "detail": "An unexpected error occurred. Quote the traceId when contacting support.", "instance": "/api/v1/main/flows", "traceId": "4bf92f3577b34da6a3ce929d0e0e4736"}Quote the traceId when reporting the problem. The errors member is never populated on a server error.
Unknown types
The catalog below grows as new kinds of failure are given a type of their own, so handle any type you do not recognise by its status class: a 4xx is something to fix in the request, a 5xx is something to retry or report. Types already published are never removed and never change meaning, so code written against the catalog keeps working.
Catalog
Types marked Cloud and Enterprise Edition are returned only by those editions. Every other type is returned by all editions.
Request payload
| Type | Status | Title |
|---|---|---|
invalid-json | 422 | Invalid JSON |
invalid-plugin-type | 422 | Invalid plugin type |
invalid-format | 422 | Invalid value format |
invalid-request-body | 422 | Invalid request body |
invalid-argument | 422 | Invalid argument |
Request line and query string
| Type | Status | Title |
|---|---|---|
bad-request | 400 | Bad request |
invalid-query-parameter | 400 | Invalid query parameter |
invalid-query-filters | 400 | Invalid query filters |
Entity validation
| Type | Status | Title |
|---|---|---|
validation-failed | 422 | Validation failed |
invalid-entity | 422 | Invalid entity |
bulk-validation-failed | 400 | Bulk validation failed |
Authentication and authorization
| Type | Status | Title |
|---|---|---|
unauthenticated | 401 | Authentication required |
forbidden | 403 | Access denied |
Resource state
| Type | Status | Title |
|---|---|---|
not-found | 404 | Resource not found |
conflict | 409 | Conflict |
entity-already-exists | 409 | Entity already exists |
resource-expired | 410 | Resource has expired |
locked | 423 | Resource is locked |
Protocol-level rejections
| Type | Status | Title |
|---|---|---|
method-not-allowed | 405 | Method not allowed |
not-acceptable | 406 | Not acceptable |
payload-too-large | 413 | Payload too large |
unsupported-media-type | 415 | Unsupported media type |
too-many-requests | 429 | Too many requests |
AI Copilot
| Type | Status | Title |
|---|---|---|
ai-request-failed | 422 | AI request failed |
Server errors
| Type | Status | Title |
|---|---|---|
internal-error | 500 | Internal server error |
migration-required | 503 | Migration required |
service-unavailable | 503 | Service unavailable |
timeout | 504 | Operation timed out |
Cloud and Enterprise Edition
| Type | Status | Title |
|---|---|---|
feature-disabled | 403 | Feature disabled by license |
license-limit-exceeded | 403 | License limit reached |
resource-leased | 423 | Resource is leased |
invalid-credentials | 400 | Invalid credentials |
password-policy-violation | 422 | Password policy not met |
policy-violation | 403 | Policy violation |
app-error | 422 | App error |
Was this page helpful?