Prevent AlreadyRunningBackfill error caused by invalid date range request#66874
Conversation
…m_date is after to_date
- ambigous meaning of InvalidBackfillDate
…x/backfill-invalid-date-range-validation
|
Hi maintainer, this PR was merged without a milestone set.
|
Backport failed to create: v3-2-test. View the failure log Run detailsNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
You can attempt to backport this manually by running: cherry_picker 1536238 v3-2-testThis should apply the commit to the v3-2-test branch and leave the commit in conflict state marking After you have resolved the conflicts, you can continue the backport process by running: cherry_picker --continueIf you don't have cherry-picker installed, see the installation guide. |
…te range request (apache#66874) When a backfill is requested with from_date after to_date, the Backfill record was committed before _get_info_list() returned an empty list, leaving an orphaned record that blocked subsequent backfills with AlreadyRunningBackfill until the scheduler's 2-minute cleanup ran. Add an InvalidBackfillDateRange exception and validate from_date <= to_date at the top of _validate_backfill_params(), before any DB operations. (cherry picked from commit 1536238)
…te range request (#66874) (#67250) * Fix OTel timer metrics using Gauge instead of Histogram (#64207) (#66865) * Fix OTel timer metrics using Gauge instead of Histogram * Use ExponentialBucketHistogramAggregation for timing metrics * Use public API import path for ExponentialBucketHistogramAggregation and fix histogram map isolation (cherry picked from commit b2dadd2) Co-authored-by: namratachaudhary <namratachaudhary@users.noreply.github.com> * [v3-2-test] Prevent AlreadyRunningBackfill error caused by invalid date range request (#66874) When a backfill is requested with from_date after to_date, the Backfill record was committed before _get_info_list() returned an empty list, leaving an orphaned record that blocked subsequent backfills with AlreadyRunningBackfill until the scheduler's 2-minute cleanup ran. Add an InvalidBackfillDateRange exception and validate from_date <= to_date at the top of _validate_backfill_params(), before any DB operations. (cherry picked from commit 1536238) --------- Co-authored-by: Rahul Vats <43964496+vatsrahul1001@users.noreply.github.com> Co-authored-by: namratachaudhary <namratachaudhary@users.noreply.github.com> Co-authored-by: Park Jiwon <57484954+david-parkk@users.noreply.github.com>
Summary
Fix
RuntimeErrorwhen creating a backfill withfrom_dateafterto_dateby adding explicit validation that raisesInvalidBackfillDateRangeearly, before any DB operations are attempted.Problem
When a backfill is requested with
from_dateafterto_date(e.g.from_date=2026-05-13,to_date=2026-05-12,from_date>to_date), the following chain of failures occurs:When a backfill is requested with from_date after to_date,
_validate_backfill_params()passes without error. The Backfill record is committed to the DB (session.commit()) before_get_info_list()iscalled. Since
_get_info_list()returns an empty list for an invalid date range, aRuntimeError("No runs to create for Dag ...")is raised — but the Backfill record already exists in the DB withcompleted_at=None and no associated BackfillDagRun records.
As a result, any subsequent backfill attempt for the same Dag immediately fails with AlreadyRunningBackfill, even though no DagRuns were ever created. The scheduler's
_mark_backfills_complete()doeseventually clean up such orphaned records (via the created_at < initializing_cutoff guard — 2 minutes), but until then the Dag is effectively locked for backfilling.
As a consequence of the above, the UI's backfill list shows the empty backfill as still running. Any new backfill attempt triggers an "Another backfill is running" popup — even though no actual runs
exist — leaving users unable to identify what went wrong or when it will resolve.
Before
no backfill data but backfill processing message

Changes
models/backfill.pyInvalidBackfillDateRangeexception class to distinguish date range errors from the existingInvalidBackfillDate(which covers future date requests)from_date > to_datecheck at the top of_validate_backfill_params(), before any DB access — consistent with the "fail fast on bad input" principlefrom_date > to_dateand future date check) together, followed by DAG structure checks (depends_on_past) and config validation. This ordering matches the general convention of validating raw inputs before inspecting DAG internalsroutes/public/backfills.pyInvalidBackfillDateRangetoimportand bothexceptblocks increate_backfillandcreate_backfill_dry_run, so it is converted to a 400RequestValidationErrorAfter
no backfill data and no message

Discussion
Exception message datetime format
The error message uses
datetime.isoformat():This format was adopted by referencing other parts of the codebase (e.g.
timetables/base.py,utils/log/file_task_handler.py), but I'm not certain it is the right convention for exception messages specifically — the existingInvalidBackfillDatedoes not include date values at all ("Backfill cannot be executed for future dates."). Would appreciate guidance on whether to keep the values for debuggability or simplify to a static message.Was generative AI tooling used to co-author this PR?
claude
I'm happy to make any adjustments based on your feedback. Thank you to the maintainers for taking the time to review this contribution!