1fanwang commented on code in PR #66888:
URL: https://github.com/apache/airflow/pull/66888#discussion_r3399850331
##########
airflow-core/src/airflow/api_fastapi/common/exceptions.py:
##########
@@ -108,6 +108,38 @@ def _is_dialect_matched(self, exc: IntegrityError) -> bool:
return False
+class DataErrorHandler(BaseErrorHandler[DataError]):
+ """
+ Translate ``sqlalchemy.exc.DataError`` into a 422 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 422 with the underlying database error
+ surfaced via ``orig_error`` rather than a generic 500.
+ """
+
+ def __init__(self):
+ super().__init__(DataError)
+
+ def exception_handler(self, request: Request, exc: DataError):
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail={
+ "reason": "Value rejected by database",
Review Comment:
Added in 0dc3e9f0cb — the statement and DB error are now logged under a
lookup id, mirroring `_UniqueConstraintErrorHandler`.
##########
airflow-core/src/airflow/api_fastapi/common/exceptions.py:
##########
@@ -108,6 +108,38 @@ def _is_dialect_matched(self, exc: IntegrityError) -> bool:
return False
+class DataErrorHandler(BaseErrorHandler[DataError]):
+ """
+ Translate ``sqlalchemy.exc.DataError`` into a 422 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 422 with the underlying database error
+ surfaced via ``orig_error`` rather than a generic 500.
+ """
+
+ def __init__(self):
+ super().__init__(DataError)
+
+ def exception_handler(self, request: Request, exc: DataError):
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail={
+ "reason": "Value rejected by database",
+ "statement": str(exc.statement),
+ "orig_error": str(exc.orig),
+ "message": (
+ "Database rejected the payload. Reduce the field size, or "
Review Comment:
Done in 0dc3e9f0cb — same generic message + lookup id as the
unique-constraint handler.
##########
airflow-core/src/airflow/api_fastapi/common/exceptions.py:
##########
@@ -108,6 +108,38 @@ def _is_dialect_matched(self, exc: IntegrityError) -> bool:
return False
+class DataErrorHandler(BaseErrorHandler[DataError]):
+ """
+ Translate ``sqlalchemy.exc.DataError`` into a 422 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 422 with the underlying database error
+ surfaced via ``orig_error`` rather than a generic 500.
+ """
+
+ def __init__(self):
+ super().__init__(DataError)
+
+ def exception_handler(self, request: Request, exc: DataError):
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail={
+ "reason": "Value rejected by database",
+ "statement": str(exc.statement),
+ "orig_error": str(exc.orig),
Review Comment:
Done in 0dc3e9f0cb — `statement`/`orig_error` are gated behind
`expose_stacktrace`, with tests for both False and True.
##########
airflow-core/src/airflow/api_fastapi/common/exceptions.py:
##########
@@ -108,6 +108,38 @@ def _is_dialect_matched(self, exc: IntegrityError) -> bool:
return False
+class DataErrorHandler(BaseErrorHandler[DataError]):
+ """
+ Translate ``sqlalchemy.exc.DataError`` into a 422 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 422 with the underlying database error
+ surfaced via ``orig_error`` rather than a generic 500.
+ """
+
+ def __init__(self):
+ super().__init__(DataError)
+
+ def exception_handler(self, request: Request, exc: DataError):
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail={
+ "reason": "Value rejected by database",
+ "statement": str(exc.statement),
+ "orig_error": str(exc.orig),
+ "message": (
+ "Database rejected the payload. Reduce the field size, or "
+ "ask an operator to widen the column type on MySQL "
+ "(e.g. MEDIUMTEXT / LONGTEXT)."
+ ),
+ },
+ )
Review Comment:
Done in 0dc3e9f0cb — reworded to be generic; the size-specific phrasing is
gone.
--
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]