neel-astro opened a new pull request, #72327:
URL: https://github.com/apache/airflow/pull/72327

   ### Why
   
   `AssetEventDagRunReference.partition_key` was added in 3.3.0 (#69115) but 
registered under the already-released `2026-04-06` Execution API version. 
Cadwyn applies a version's downgrade instructions only for clients *older* than 
that version, so a client requesting exactly `2026-04-06` still receives the 
field.
   
   Task SDK 1.2.x (Airflow 3.2.x) speaks `2026-04-06`, and its 
`AssetEventDagRunReference` has no `partition_key`, with `extra="forbid"`. 
Every asset-triggered task run by a 3.2.x worker against a 3.3.x API server 
fails before it starts:
   
   ```
   airflow/sdk/api/client.py:231 in start
       return TIRunContext.model_validate_json(resp.read())
   pydantic_core._pydantic_core.ValidationError: 1 validation error for 
TIRunContext
   dag_run.consumed_asset_events.0.partition_key
     Extra inputs are not permitted [type=extra_forbidden, input_value=None, 
input_type=NoneType]
   ```
   
   The value is `null`, so this affects every asset-triggered run, not just 
partitioned assets. The task dies at supervision start.
   
   Reading `partition_key` out of each released task-sdk wheel's 
`airflow/sdk/api/datamodels/_generated.py`:
   
   | task-sdk | API_VERSION | `AssetEventDagRunReference` |
   |---|---|---|
   | 1.1.5 (3.1.x) | 2025-11-05 | absent |
   | 1.2.0 (3.2.0) | 2026-04-06 | **absent** |
   | 1.2.1 (3.2.1) | 2026-04-06 | **absent** |
   | 1.2.2 (3.2.2) | 2026-04-06 | **absent** |
   | 1.3.0 (3.3.0) | 2026-06-30 | present |
   | 1.3.1 (3.3.1) | 2026-06-30 | present |
   
   `AssetEventDagRunReference` is the only one of the five models in 
`AddPartitionKeyField` that did not gain the field at `2026-04-06`. `DagRun`, 
`AssetEventResponse`, `TriggerDAGRunPayload` and `DagRunAssetReference` all 
carry it in 1.2.0+, so their gating is correct and is left alone.
   
   ### What
   
   Move the `AssetEventDagRunReference.partition_key` schema instruction and 
its `consumed_asset_events` response converter out of `v2026_04_06.py` into a 
new `AddConsumedAssetEventPartitionKeyField` in `v2026_06_30.py`, matching how 
the sibling `AddPartitionDateField` handles `DagRun.partition_date` (also new 
in 3.3.0). The HEAD datamodel and the generated Task SDK models are unchanged.
   
   Both halves of the gate move together. The `schema(...).didnt_exist` 
instruction drives the per-version OpenAPI document and the converter mutates 
the wire body, so leaving either behind would ship a spec that contradicts the 
response.
   
   Only `TIRunContext` gets a converter, where the two siblings in the same 
file register three each. `DagRun.safe_extract_from_orm` defaults 
`consumed_asset_events` to `[]` whenever the relationship is not already 
loaded, and `PATCH /task-instances/{id}/run` is the only route that loads it, 
so bare `DagRun` responses never carry one. Two tests in 
`versions/v2026_06_30/test_dag_runs.py` pin that invariant so it fails loudly 
if a future change adds eager loading there.
   
   ### Tests
   
   `TestConsumedEventPartitionKeyBackwardCompat` moves to the `v2026_06_30` 
suite, where `old_ver_client` is pinned to exactly `2026-04-06` — the version 
Task SDK 1.2.x sends. In its previous home it ran at `2025-11-05`, older than 
the mis-placed gate, which is why this passed CI.
   
   Three assertions cover the three ways this can go wrong:
   
   - a `2026-04-06` client gets the event-level `partition_key` stripped while 
the Dag-run-level `partition_key` survives, in one response (under-moving the 
gate)
   - a client at exactly `2026-06-30` and a HEAD client both still receive it 
(over-moving the gate would silently break 1.3.x, which sends `2026-06-30` and 
carries the field)
   - the served OpenAPI for `AssetEventDagRunReference` matches the wire body 
at both versions (moving only one half of the gate)
   
   Beyond the suite, the released 1.2.2 `TIRunContext` — the model that raised 
the traceback above — was loaded from its wheel and used to validate a real 
captured `2026-04-06` response body: it accepts the server's current output and 
still rejects it once `partition_key` is re-injected. That checks response 
bytes against the real released client model; it is not a live 1.2.x worker 
running end to end.
   
   One pre-existing test fixture changed: `old_ver_client` in 
`versions/v2026_06_30/test_task_instances.py` moved from `2026-06-16` to 
`2026-04-06`. This is behaviour-preserving — `2026-06-16` was never a 
registered version and resolved to the same bundle — and it aligns the module 
with its siblings in that directory, which already pin `2026-04-06`.
   
   ### Backport
   
   3.3.0 and 3.3.1 are both released with this bug, so a `main`-only fix does 
not help anyone currently affected. Requesting the **3.3.2** milestone.
   
   related: #69115
   
   related: #71861 — that PR fixes a different class of gap in the same two 
files (missing registrations on the compat previous-run route and nested 
`created_dagruns`). The two are semantically orthogonal, but both touch 
`remove_partition_key_from_dag_run`, so whichever merges second will conflict 
there. The resolution is to keep the `consumed_asset_events` loop deleted and 
keep that PR's added converters; re-adding the loop alongside the new 
`VersionChange` is a silent no-op that the test suite cannot detect.
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Code (Opus 5)
   
   Generated-by: Claude Code (Opus 5) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to