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]