Marking a Dag run success/failed returns 409 Conflict on first attempt (3.3.1 regression) · Issue #73152 · apache/airflow · GitHub
Skip to content

Marking a Dag run success/failed returns 409 Conflict on first attempt (3.3.1 regression) #73152

Description

@DianaHov

Under which category would you file this issue?

Airflow Core

Apache Airflow version

3.3.1

What happened and how to reproduce it?

Marking a Dag run as success or failed from the UI returns 409 Conflict
("Update Dag Run Request Failed"), but the change is applied anyway - the run
and its task instances are updated, and the UI shows an error for an operation
that actually succeeded.

It only happens the first time a given run is marked. Marking the same run
again succeeds with no error.

The api-server log shows:

Error with id ..., statement: INSERT INTO dag_run_note (user_id, dag_run_id, content, created_at, updated_at) VALUES (...)

i.e. a duplicate-key violation on dag_run_note, surfaced as 409 by
_UniqueConstraintErrorHandler. It happens even with the Note field left empty.

Works correctly in 3.3.0.

To reproduce:

  1. Fresh 3.3.1 install, Postgres, any Dag.
  2. Trigger a run and leave it un-started.
  3. Mark the run as success (or failed) from the UI, leaving the Note box empty.
  4. The red "Conflict" toast appears; the run is nevertheless marked and its
    task instances updated.
  5. Mark the same run again - this time it succeeds silently.

What you think should happen instead?

The request should return 200 and no duplicate insert should be attempted.


The cause is in _set_dag_run_terminal_state
(airflow-core/src/airflow/api/common/mark_tasks.py):

for ti in pending_normal_tis:
    ti.set_state(TaskInstanceState.SKIPPED)

TaskInstance.set_state is decorated with @provide_session and no session is
passed here, so it opens its own session, calls session.merge(self) and
commits it. TaskInstance.dag_run is lazy="joined", so that merge cascades
TI → DagRun → dag_run_note and carries the still-unflushed DagRunNote into
the second session, which commits it. The request's session then commits its
own copy of the same row, and the second insert violates dag_run_note_pkey.

This surfaces in 3.3.1 because patch_dag_run now applies the note before the
state, so a note is attached to the DagRun at the moment that merge happens. In
3.3.0 the state ran first and there was nothing to cascade.

The fix is to pass the session through:

for ti in pending_normal_tis:
    ti.set_state(TaskInstanceState.SKIPPED, session=session)

That keeps the note-before-state ordering intact and produces a single insert.
Verified locally on 3.3.1: the 409 is gone, and the run and its task instances
update as expected.

Operating System

macOS

Deployment

Other

Apache Airflow Provider(s)

No response

Versions of Apache Airflow Providers

No response

Official Helm Chart version

Not Applicable

Kubernetes Version

No response

Helm Chart configuration

No response

Docker Image customizations

No response

Anything else?

No response

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:bugThis is a clearly a bugneeds-triagelabel for new issues that we didn't triage yet

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions