1fanwang commented on code in PR #66888:
URL: https://github.com/apache/airflow/pull/66888#discussion_r3286592835


##########
airflow-core/newsfragments/66888.bugfix.rst:
##########
@@ -0,0 +1 @@
+Translate ``sqlalchemy.exc.DataError`` (raised when the database rejects an 
INSERT/UPDATE because a value exceeds the column type or is out of range) to an 
actionable ``413 Content Too Large`` / ``422 Unprocessable Entity`` response on 
both the public REST API and the task-execution API, instead of a generic ``500 
Internal Server Error``. This covers every write endpoint (DagRun ``conf``, 
Connection ``extra``, Variable ``val``, XCom ``value``, TaskInstance ``note``, 
HITL fields, and so on) on every backend automatically.

Review Comment:
   Done in 3f8fdc6a20.



##########
airflow-core/src/airflow/api_fastapi/common/exceptions.py:
##########
@@ -108,6 +108,46 @@ def _is_dialect_matched(self, exc: IntegrityError) -> bool:
         return False
 
 
+class _DataErrorHandler(BaseErrorHandler[DataError]):

Review Comment:
   Done in 3f8fdc6a20 — renamed `_DataErrorHandler` → `DataErrorHandler`.



##########
airflow-core/src/airflow/api_fastapi/execution_api/app.py:
##########
@@ -262,6 +262,18 @@ def custom_generate_unique_id(route: APIRoute):
 
     app.generate_and_include_versioned_routers(execution_api_router)
 
+    # Same translation as the public API: DB-rejected payloads become 4xx with 
an
+    # actionable hint instead of being swallowed by the generic 500 handler 
below.
+    # The narrower ``Callable[[Request, DataError], ...]`` signature is 
widened to
+    # ``Callable[[Request, Exception], ...]`` by Starlette at registration 
time;
+    # the same variance pattern is masked by type erasure in
+    # ``core_api/app.py``'s ``ERROR_HANDLERS`` loop.
+    from sqlalchemy.exc import DataError
+
+    from airflow.api_fastapi.common.exceptions import _DataErrorHandler
+
+    app.add_exception_handler(DataError, 
_DataErrorHandler().exception_handler)  # type: ignore[arg-type]

Review Comment:
   Done in 3f8fdc6a20 — removed the entire manual block from 
`create_task_execution_api_app`. `init_error_handlers(task_exec_api_app)` at 
`airflow-core/src/airflow/api_fastapi/app.py:107` already loops over 
`ERROR_HANDLERS` so the new `DataErrorHandler` is picked up on both apps 
automatically.



##########
airflow-core/src/airflow/api_fastapi/common/exceptions.py:
##########
@@ -108,6 +108,46 @@ def _is_dialect_matched(self, exc: IntegrityError) -> bool:
         return False
 
 
+class _DataErrorHandler(BaseErrorHandler[DataError]):
+    """
+    Translate ``sqlalchemy.exc.DataError`` into an actionable HTTP response.
+
+    ``DataError`` wraps the database rejecting an INSERT/UPDATE because a value
+    exceeds the column's declared type (MySQL ``1406 Data too long``, Postgres
+    ``value too long for type``) or is out of range (MySQL ``1264 Out of range
+    value``, Postgres ``numeric field overflow``). The wrapped value came from
+    request input that passed Pydantic validation, so the failure is always a
+    client problem — translate to a 4xx with an actionable hint rather than
+    surfacing as a generic 500.
+    """
+
+    _TOO_LARGE_MARKERS: tuple[str, ...] = ("too long", "too large", "too big")

Review Comment:
   Done in 3f8fdc6a20 — went with the simpler 422-fallback path. The marker 
list is gone, every `DataError` now returns 422 with the underlying error 
surfaced in `orig_error`.



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