illiakrauchanka opened a new issue, #71497:
URL: https://github.com/apache/airflow/issues/71497

   ### Under which category would you file this issue?
   
   Airflow Core
   
   ### Apache Airflow version
   
   3.3.0
   
   ### What happened and how to reproduce it?
   
   ### If "Other Airflow 2/3 version" selected, which one?
   
   _No response_
   
   ### What happened?
   
   On a PostgreSQL metadata database, the UI DAG run stats endpoint returns 
HTTP 500 for every request:
   
   `GET /ui/dags/{dag_id}/dagRuns/{dag_run_id}/stats`
   
   ```
   [error] Exception in ASGI application [uvicorn.error] 
loc=httptools_impl.py:426
   Traceback (most recent call last):
     ...
     File ".../airflow/api_fastapi/core_api/routes/ui/dag_runs.py", line 63, in 
get_dag_run_stats
     File ".../airflow/api_fastapi/core_api/services/ui/dag_run.py", line 55, 
in compute_duration_stats
     File ".../airflow/api_fastapi/core_api/services/ui/dag_run.py", line 50, 
in _percentile
   TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float'
   ```
   
   Root cause is a type mismatch between the query and the helper that consumes 
it.
   
   `get_dag_run_stats` (`core_api/routes/ui/dag_runs.py`) selects the SQL 
expression form of the duration:
   
   ```python
   durations = [
       d
       for d in session.scalars(
           select(DagRun.duration.expression)
           .where(...)
           .limit(100)
       )
       if d is not None
   ]
   return DagRunStatsResponse(duration=compute_duration_stats(durations))
   ```
   
   `DagRun.duration.expression` (`models/dagrun.py`) is dialect dependent:
   
   * PostgreSQL: `func.extract("epoch", cls.end_date - cls.start_date)` -> SQL 
`numeric` -> psycopg returns `decimal.Decimal`
   * MySQL: `func.timestampdiff(SECOND, ...)` -> integer
   * SQLite: `(julianday(end) - julianday(start)) * 86400` -> float
   
   `compute_duration_stats` is annotated `durations: list[float]` and mixes the 
values with plain floats:
   
   ```python
   def _percentile(p: float) -> float:
       idx = (len(sorted_d) - 1) * p / 100
       lo = int(idx)
       hi = min(lo + 1, len(sorted_d) - 1)
       return sorted_d[lo] + (sorted_d[hi] - sorted_d[lo]) * (idx - lo)
   ```
   
   With `Decimal` values, `Decimal * float` raises `TypeError`. This is not 
limited to the interpolating case: with a single completed run, `idx - lo` is 
`0.0` and `Decimal(0) * 0.0` raises as well, so any DAG that has at least one 
completed run fails.
   
   Impact is limited to this endpoint, which the UI calls when a DAG's run 
stats are displayed. Scheduling, task execution and the public API are 
unaffected.
   
   ### What you think should happen instead?
   
   The endpoint should return duration statistics regardless of the metadata 
database backend.
   
   Coercing at the query boundary keeps `compute_duration_stats` matching its 
`list[float]` annotation:
   
   ```python
   durations = [float(d) for d in session.scalars(...) if d is not None]
   ```
   
   Alternatively `_percentile` could operate on `Decimal` consistently, but the 
boundary cast looks closer to the intent of the existing type hints.
   
   ### How to reproduce
   
   1. Deploy Airflow 3.3.0 with a PostgreSQL metadata database.
   2. Let at least one DAG run reach `success` or `failed`.
   3. Call `GET /ui/dags/{dag_id}/dagRuns/{dag_run_id}/stats`, or open the DAG 
in the UI so the stats panel loads.
   4. The request fails with HTTP 500 and the traceback above.
   
   Not reproducible on SQLite or MySQL, where the same expression yields 
`float` / `int`.
   
   ### Operating System
   
   Debian GNU/Linux 12 (bookworm) — official `apache/airflow:3.3.0` image
   
   ### Versions of Apache Airflow Providers
   
   _No response_
   
   ### Deployment
   
   Official Apache Airflow Helm Chart
   
   ### Deployment details
   
   Helm chart 1.22.0 with `defaultAirflowTag` / `airflowVersion` pinned to 
3.3.0, KubernetesExecutor and CeleryExecutor deployments both affected, 
PostgreSQL 17.9 (Amazon RDS), Python 3.13.
   
   ### Anything else?
   
   Occurs on every request to the endpoint once a DAG has completed runs.
   
   ### Are you willing to submit PR?
   
   - [ ] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
   
   
   ### What you think should happen instead?
   
   _No response_
   
   ### Operating System
   
   _No response_
   
   ### Deployment
   
   None
   
   ### 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
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
   


-- 
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