For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append .md to any kestra.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

MemberAlways presentDescription
typeyesStable identifier of the kind of problem, as a URI that resolves to its page below. This is the only member to branch on.
titleyesShort summary of the kind of problem. Identical for every occurrence of a given type, and never parameterised.
statusyesThe HTTP status code, repeated in the body for convenience.
detailyesExplanation of this particular occurrence, written for a human.
instanceyesPath of the request that produced the problem.
errorsnoField-level or per-item errors, when several problems are reported at once.
traceIdnoCorrelation 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.

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"
}
]
}
MemberDescription
detailWhat is wrong with this field or item.
pointerRFC 6901 JSON Pointer locating the field in the submitted document.
pathFriendlier locator that names tasks and inputs by their id. Not a JSON Pointer.
typeThe 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

TypeStatusTitle
invalid-json422Invalid JSON
invalid-plugin-type422Invalid plugin type
invalid-format422Invalid value format
invalid-request-body422Invalid request body
invalid-argument422Invalid argument

Request line and query string

TypeStatusTitle
bad-request400Bad request
invalid-query-parameter400Invalid query parameter
invalid-query-filters400Invalid query filters

Entity validation

TypeStatusTitle
validation-failed422Validation failed
invalid-entity422Invalid entity
bulk-validation-failed400Bulk validation failed

Authentication and authorization

TypeStatusTitle
unauthenticated401Authentication required
forbidden403Access denied

Resource state

TypeStatusTitle
not-found404Resource not found
conflict409Conflict
entity-already-exists409Entity already exists
resource-expired410Resource has expired
locked423Resource is locked

Protocol-level rejections

TypeStatusTitle
method-not-allowed405Method not allowed
not-acceptable406Not acceptable
payload-too-large413Payload too large
unsupported-media-type415Unsupported media type
too-many-requests429Too many requests

AI Copilot

TypeStatusTitle
ai-request-failed422AI request failed

Server errors

TypeStatusTitle
internal-error500Internal server error
migration-required503Migration required
service-unavailable503Service unavailable
timeout504Operation timed out

Cloud and Enterprise Edition

TypeStatusTitle
feature-disabled403Feature disabled by license
license-limit-exceeded403License limit reached
resource-leased423Resource is leased
invalid-credentials400Invalid credentials
password-policy-violation422Password policy not met
policy-violation403Policy violation
app-error422App error

Was this page helpful?