Configure Retry Strategies for Transient Task Failures

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.

Retries automatically rerun failed tasks. Each retry creates a new task run attempt based on the retry configuration defined in the flow.

Task-level retries

Example

This task runs up to 5 times total (1 initial attempt + up to 4 retries) with a 15-minute interval between attempts:

- id: retry_sample
type: io.kestra.plugin.core.log.Log
message: my output for task {{ task.id }}
timeout: PT10M
retry:
type: constant
maxAttempts: 5
interval: PT15M

Constant retry, 4 attempts, 0.25-second interval — uses {{ taskrun.attemptsCount }} to conditionally exit:

id: retry
namespace: company.team
description: This flow retries 4 times and succeeds on the 5th attempt
tasks:
- id: failed
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- 'if [ "{{ taskrun.attemptsCount }}" -eq 4 ]; then exit 0; else exit 1; fi'
retry:
type: constant
interval: PT0.25S
maxAttempts: 5
maxDuration: PT1M
warningOnRetry: true
errors:
- id: never_happen
type: io.kestra.plugin.core.log.Log
message: "Never happened {{ task.id }}"

Timeout vs. Max Retry Duration

  • timeout: Maximum duration for a single task attempt (initial or retry). If exceeded, the attempt fails.
  • retry.maxDuration: Maximum total time allowed for the task, including all attempts and delays. Once exceeded, retries stop.

Example: With timeout: 10m and maxDuration: 30m:

  • Each attempt can last up to 10 minutes.
  • The overall retries stop after 30 minutes in total.

Retry options

NameTypeDescription
typestringRetry strategy: constant, exponential, or random.
maxAttemptsintegerMaximum number of attempts, including the initial run. maxAttempts: 1 means no retry; maxAttempts: 2 means one retry after the initial attempt.
maxDurationDurationMaximum total time for the task, across all attempts.
warningOnRetryBooleanMarks execution as WARNING if retries occurred (default: false).
behaviorstringWhat to retry when set on a flowable task. RETRY_FAILED_TASK (default) retries only the failed child task. RETRY_FLOWABLE reruns the entire flowable block from the start. See Retry on flowable tasks.

Duration format

Durations use ISO 8601 format (weeks, months, years not supported). Examples:

ValueDescription
PT0.25S250 ms
PT2S2 seconds
PT1M1 minute
PT3.5H3 hours, 30 minutes
P6DT4H6 days, 4 hours

Retry on flowable tasks

Flowable tasks such as Sequential and Parallel accept a retry block with a behavior property that controls what is retried when a child task fails.

Default behavior: RETRY_FAILED_TASK

By default (behavior: RETRY_FAILED_TASK), a retry on a flowable task does not rerun the group. It sets the default retry policy that child tasks inherit when they have no retry of their own. Only the failed child is retried; earlier tasks do not run again.

id: token_and_api
namespace: company.team
tasks:
- id: group
type: io.kestra.plugin.core.flow.Sequential
retry:
type: constant
maxAttempts: 2
interval: PT1S
tasks:
- id: get_token
type: io.kestra.plugin.core.output.OutputValues
values:
result: "{{ now() }}"
- id: call_api
type: io.kestra.plugin.core.execution.Fail
errorMessage: "Token expired"

If call_api fails, Kestra retries only call_api. get_token does not run again, and each retry of call_api uses the same token from the first run. A token that expires between the two tasks is never refreshed this way.

Rerun the whole block: RETRY_FLOWABLE

Set behavior: RETRY_FLOWABLE to rerun the entire flowable block from the start when any child task fails. All child task runs from the previous attempt are discarded and the group begins again.

id: token_and_api
namespace: company.team
tasks:
- id: group
type: io.kestra.plugin.core.flow.Sequential
retry:
type: constant
maxAttempts: 3
interval: PT1S
behavior: RETRY_FLOWABLE
tasks:
- id: get_token
type: io.kestra.plugin.core.output.OutputValues
values:
result: "{{ now() }}"
- id: call_api
type: io.kestra.plugin.core.execution.Fail
errorMessage: "Calling API with {{ outputs.get_token.values.result }}"

When call_api fails, get_token runs again on the next attempt, producing a fresh token.

Behavior by flowable type:

  • Sequential, Parallel, WorkingDirectory, AllowFailure, If, Switch, Dag — all child tasks rerun from the start on each attempt. If and Switch re-evaluate their condition or value, so a retry can take a different branch.
  • Loop — only the failed iteration restarts from its first child task. Other iterations are not touched.
  • AllowFailure and tasks with allowFailure: true — failure is allowed only after the last attempt has been exhausted.

RETRY_FLOWABLE is rejected on runnable (non-flowable) tasks and at flow level.

Retry a group as a new execution

To retry a set of tasks as a completely new child execution, use a Subflow with retry. Each retry creates a new execution, so all tasks in the subflow run again from the start with a separate execution ID.

id: parent
namespace: company.team
tasks:
- id: group
type: io.kestra.plugin.core.flow.Subflow
namespace: company.team
flowId: get_token_and_call_api
retry:
type: constant
maxAttempts: 2
interval: PT1S

Token refresh pattern

For the specific case of a short-lived token that may expire between tasks, Credentials (Enterprise Edition and Cloud) is the cleaner solution. Kestra fetches and refreshes the token automatically, so every retry gets a valid one without needing a get_token task at all.

id: api_call
namespace: company.team
tasks:
- id: call_api
type: io.kestra.plugin.core.http.Request
uri: https://api.example.com/v1/data
options:
auth:
type: BEARER
token: "{{ credential('my_oauth') }}"
retry:
type: constant
maxAttempts: 3
interval: PT1S

Retry types

constant

Retries at fixed intervals. Example: with interval: PT10M, retries occur every 10 minutes.

NameTypeDescription
intervalDurationDelay between attempts.

exponential

Wait time increases after each retry (e.g., 30s, 1m, 2m, …).

NameTypeDescription
intervalDurationBase interval between attempts.
maxIntervalDurationMaximum interval allowed.
delayFactorDoubleMultiplier (default: 2). Example: interval 30s → 30s, 1m, 2m, 4m…

random

Randomized delays within bounds.

NameTypeDescription
minIntervalDurationMinimum delay.
maxIntervalDurationMaximum delay.

Configuring retries globally

You can configure retries globally for all tasks in Kestra:

kestra:
plugins:
configurations:
- type: io.kestra
values:
retry:
type: constant
maxAttempts: 3
interval: PT30S

Flow-level retries

Flow-level retries restart either the entire execution or only failed tasks, controlled by the behavior property:

  1. CREATE_NEW_EXECUTION: Start a new execution.
  2. RETRY_FAILED_TASK: Retry only the failed task.
id: flow_level_retry
namespace: company.team
retry:
maxAttempts: 3
behavior: CREATE_NEW_EXECUTION # or RETRY_FAILED_TASK
type: constant
interval: PT1S
tasks:
- id: fail_1
type: io.kestra.plugin.core.execution.Fail
allowFailure: true
- id: fail_2
type: io.kestra.plugin.core.execution.Fail
  • With CREATE_NEW_EXECUTION, the execution attempt increases.
  • With RETRY_FAILED_TASK, only the task run attempt increases.

Retry vs. Restart vs. Replay

Retry is the only automatic mechanism. Restart and Replay are both manual, initiated from the UI.

ConceptScopeTriggerNew execution?
RetryTask levelAutomaticNo
RestartFlow levelManualNo
ReplayFlow or task levelManualYes

Restart reruns only the failed tasks within the same execution, keeping the same execution ID. Restart is available from the Execution overview page.

Replay starts a new execution from any task (successful or failed) and assigns it a new execution ID. Previous task outputs are reused from cache when available. Replay is available from the Actions menu on the Execution overview page and from task nodes in the Topology, Gantt, or Logs view. See the Replay documentation.

After a replay, the new execution’s Overview tab shows an Original Execution field linking back to the source run.

Was this page helpful?