You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by "Pushkal-Gupta (via GitHub)" <gi...@apache.org> on 2026/10/18 23:36:06 UTC

[PR] Fix 500 when paging task instances ordered by data interval [airflow]

Pushkal-Gupta opened a new pull request, #75026:
URL: https://github.com/apache/airflow/pull/75026

   Both task instance list endpoints offer `data_interval_start` and `data_interval_end` as attributes you can order by, and both support cursor pagination. Combining the two fails.
   
   ```
   GET /api/v2/dags/~/dagRuns/~/taskInstances?cursor=&limit=2&order_by=data_interval_start
   
   AttributeError: 'TaskInstance' object has no attribute 'data_interval_start'
   NotImplementedError: Cursor pagination cannot resolve column-form ``to_replace`` for
   ``data_interval_start``: the primary model exposes no such attribute. Add an association
   proxy, use a string alias, or sort by a primary-model column.
   ```
   
   Ordering itself is fine. Both names are `to_replace` entries pointing at `DagRun` columns, so the `ORDER BY` lands on the joined run. The failure is in encoding the cursor afterwards: `SortParam.row_value()` reads the sort key back off the result row, which is a `TaskInstance`, and neither name exists there. So the first page is fine until it has to hand out a `next_cursor`, which means the break only shows up once there is more than one page.
   
   `run_after` and `logical_date` are in the same `to_replace` map and do not break, because `TaskInstance` already exposes both as association proxies onto `dag_run`. These two were simply never added.
   
   ### The change
   
   Two more proxies alongside the existing ones, which is the fix the error message itself suggests:
   
   ```python
    run_after = association_proxy("dag_run", "run_after")
    logical_date = association_proxy("dag_run", "logical_date")
   +data_interval_start = association_proxy("dag_run", "data_interval_start")
   +data_interval_end = association_proxy("dag_run", "data_interval_end")
    team_name = association_proxy("dag_run", "team_name")
   ```
   
   No extra queries: the `dag_run` relationship is already `lazy="joined", innerjoin=True`, which is the same reason the two existing proxies are free.
   
   Nothing else picks these up. `TaskInstanceResponse` does not declare either name, so the API payload is unchanged and the spec does not move. I also checked there is no code keyed on their absence through `hasattr` or `getattr`.
   
   ### Tests
   
   Two cases, one per attribute, in `TestGetTaskInstances`. They page all the way through with `limit=2` and assert all five task instances come back exactly once, because a single request would have passed without exercising the encode at all.
   
   Paging alone turned out not to be enough of an assertion. All five task instances belong to one Dag run, so they tie on the data interval and the primary-key tie-break would page them correctly even if the interval had encoded as null. Worse, the shared fixture leaves the run's data interval NULL, so that is exactly what the first version of the test was doing. It now sets a real interval on the run and decodes the first `next_cursor` to check the boundary value went in, which is the part that was actually broken.
   
   Both fail without the change, with the `NotImplementedError` above. `test_task_instances.py` goes from 511 to 513 passed.
   
   ### Also looked at
   
   The other `to_replace` entries of this shape across `api_fastapi`. `map_index` and `rendered_map_index` resolve on `TaskInstance`, the `dag_run.py` sorts use the string form which takes a different and safe path in `row_value`, and `/dags` has two column-form entries but does not use cursor pagination, so it never reaches the encode.
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes - Claude Code (Opus 5)


-- 
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: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org