Skip to content

Airflowctl dags trigger fails with extra_forbidden against Airflow < 3.2.0 #70327

Description

@namita-can

Airflow CTL Version

Latest stable version

Airflow CTL Command

airflowctl dags trigger example_simplest_dag --dag-run-id <run_id> --env production

Keyring Backend / Version

Keyring Backend/Headless

Auth Type

Token

What is the current behaviour?

airflowctl dags trigger fails against any Airflow deployment running a version earlier than 3.2.0, with:

{'type': 'extra_forbidden', 'loc': ['body', 'partition_key'], 'msg': 'Extra inputs are not permitted', 'input': None}

Root cause: DagOperations.trigger() in airflow-ctl/src/airflowctl/api/operations.py serializes the request body without exclude_none=True:

json=trigger_dag_run.model_dump(mode="json")

TriggerDAGRunPostBody includes partition_key and bundle_version, both added in Airflow 3.2.0's model. Since these default to None and are never excluded from serialization, every trigger request includes them as null regardless of the target server's Airflow version. Any server running < 3.2.0 doesn't recognize these fields and rejects the request entirely.

AssetsOperations.create_event() in the same file already handles this correctly:

json=asset_event_body.model_dump(mode="json", exclude_none=True)

Confirmed via the live OpenAPI schema on a 3.1.x deployment (curl .../openapi.json) that partition_key/bundle_version genuinely don't exist in that server's TriggerDAGRunPostBody schema, and confirmed directly against the apache/airflow source that these fields were added starting at the 3.2.0 tag (absent in 3.1.0 through 3.1.8).

What is the expected results?

airflowctl dags trigger should succeed against any Airflow API server version whose TriggerDAGRunPostBody schema it's compatible with, i.e., it shouldn't send fields the target server doesn't recognize just because the client's own model happens to declare them, when those fields were never explicitly set by the caller.

Anything else?

Steps to reproduce:

  1. Deploy Airflow 3.1.x (reproduced on 3.1.0 via Charmed Airflow on Kubernetes)
  2. airflowctl auth login --api-url <url> --env <env> --skip-keyring
  3. airflowctl dags trigger <dag_id> --dag-run-id <run_id> --env <env>
  4. Observe the extra_forbidden error

Fix confirmed locally: adding exclude_none=True to trigger()'s model_dump() call resolves the issue, tested both with and without --logical-date passed explicitly. PR incoming with the fix plus a regression test.

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions