Many failures are temporary: an API that answers 503, a database restarting, a lock held a bit too long. Retries let Airflow try again before anyone has to look at the task. A timeout covers the opposite case, a task that hangs and would otherwise hold its worker slot for hours.

Copy and paste

On one task:

from datetime import timedelta
from airflow.sdk import task

@task(
    retries=3,
    retry_delay=timedelta(minutes=5),
    retry_exponential_backoff=2.0,
    max_retry_delay=timedelta(minutes=30),
    execution_timeout=timedelta(minutes=20),
)
def call_api():
    ...

On every task of a DAG, plus a limit for the whole run:

from datetime import timedelta
import pendulum
from airflow.sdk import dag

@dag(
    schedule="0 6 * * *",
    start_date=pendulum.datetime(2026, 1, 1, tz="UTC"),
    catchup=False,
    default_args={
        "retries": 2,
        "retry_delay": timedelta(minutes=5),
        "execution_timeout": timedelta(hours=1),
    },
    dagrun_timeout=timedelta(hours=3),
)
def sales_daily():
    ...

sales_daily()

Classic operators take the same arguments, for example BashOperator(task_id="export", bash_command="...", retries=3, execution_timeout=timedelta(minutes=20)).

A sensor that waits up to six hours without holding a worker slot:

import os
from airflow.sdk import task

@task.sensor(poke_interval=300, timeout=6 * 60 * 60, mode="reschedule")
def wait_for_file() -> bool:
    return os.path.exists("/data/in/sales.csv")

What happens on a timeout

When a task exceeds execution_timeout, Airflow stops it with an AirflowTaskTimeout. A timeout counts as a failure, so the task is retried if it has retries left:

airflow.sdk.exceptions.AirflowTaskTimeout: Timeout, PID: 98357
Task instance state updated  new_state=up_for_retry

dagrun_timeout applies to the whole run: when it expires, the run is marked as failed and the tasks still running are stopped.

How long the retries wait

With retry_delay=5 minutes and retry_exponential_backoff=2.0, each wait is about twice the previous one:

Retry Wait
1st 5 to 10 minutes
2nd 10 to 20 minutes
3rd 20 to 40 minutes, capped at max_retry_delay (30 minutes above)

Airflow adds a random but repeatable part to each wait, so that tasks that failed together do not all retry in the same second. In Airflow 3.3 retry_exponential_backoff is a multiplier: 0, the default, keeps the delay constant. Older versions took True, which Airflow 3.3 still accepts and treats as 2.0.

Things to know

Tested with Airflow 3.3.2.

References