FastAPI-Pydantic校验异常:字段齐全时返回无效输入错误排查
问题排查:Pydantic模型校验通过后仍返回"Input should be a valid dictionary..."错误
问题场景
使用@model_validator(mode='before')结合model_validate校验请求是否匹配子类时,缺少必填字段能正常返回"字段缺失"提示;但字段齐全时,尽管模型校验通过、后续逻辑可执行,却抛出Input should be a valid dictionary or object to extract fields from: ('body',)错误。
示例代码与请求
请求载荷
{ "name": "BC", "connectorType": "SNOWFLAKE", "productName": "bc", "secretArn": "foobararn", "warehouse": "foobarwarehouse", "tableSchema": "foobarschema", "database": "bardatabse" }
模型代码
class SnowflakeConnector(SpotApiBaseModel): """Snowflake Connector.""" model_config = ConfigDict(from_attributes=True) secretArn: str = Field(description="AWS secret arn") warehouse: str = Field(description="Snowflake warehouse. Required for connector type: SNOWFLAKE") database: str = Field(description="Database name. Required for connector type: SNOWFLAKE") tableSchema: str = Field(description="Database table schema. Required for connector type: SNOWFLAKE") class ConnectorInterface(BaseConnector): @model_validator(mode='before') def check_allowed_products(cls, values): connector = values.get('connectorType').lower() if connector == "s3": S3Connector.model_validate(values) elif connector == "snowflake": SnowflakeConnector.model_validate(values)
异常信息
{"time": "2024-06-18T10:46:45.641Z", "l": "ERROR", "rid": "2558770a-66ff-4da0-b8a2-977afc5043e6", "org": "", "act": "", "message": "An error occurred: [{'type': 'model_attributes_type', 'loc': ('body',), 'msg': 'Input should be a valid dictionary or object to extract fields from', 'input': None, 'url': 'https://errors.pydantic.dev/2.6/v/model_attributes_type'}]", "component": {"name": "/app/common/exceptions/base_exception_handler.py", "version": "0.1.3"}, "exception": "Traceback (most recent call last):\n File \"/Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/starlette/middleware/exceptions.py\", line 68, in __call__\n await self.app(scope, receive, sender)\n File \"/Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 20, in __call__\n raise e\n File \"/Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py\", line 17, in __call__\n await self.app(scope, receive, send)\n File \"/Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/starlette/routing.py\", line 718, in __call__\n await route.handle(scope, receive, send)\n File \"/Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/starlette/routing.py\", line 276, in handle\n await self.app(scope, receive, send)\n File \"Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/starlette/routing.py\", line 66, in app\n response = await func(request)\n ^^^^^^^^^^^^^^^^^^^\n File \"/Library/Caches/pypoetry/virtualenvs/service-Qx3_L5c2-py3.12/lib/python3.12/site-packages/fastapi/routing.py\", line 273, in app\n raise RequestValidationError(_normalize_errors(errors), body=body)\nfastapi.exceptions.RequestValidationError: [{'type': 'model_attributes_type', 'loc': ('body',), 'msg': 'Input should be a valid dictionary or object to extract fields from', 'input': None, 'url': 'https://errors.pydantic.dev/2.6/v/model_attributes_type'}]"}
原因分析
问题根源在于@model_validator(mode='before')的返回规则:Pydantic要求该模式下的校验器必须返回处理后的输入值,若未显式返回,默认会返回None。当前校验器仅调用子类的model_validate完成校验,未返回原始values,导致Pydantic后续处理时拿到的输入为None,触发model_attributes_type错误。
解决方案
修改校验器,在完成子类校验后显式返回原始values:
class ConnectorInterface(BaseConnector): @model_validator(mode='before') def check_allowed_products(cls, values): connector = values.get('connectorType').lower() if connector == "s3": S3Connector.model_validate(values) elif connector == "snowflake": SnowflakeConnector.model_validate(values) # 必须返回输入值,否则Pydantic会将None作为后续处理的输入 return values
补充说明
model_validate仅做规则校验,不会修改原始values,直接返回即可。- 若需对输入值做修改(如补充默认字段),可在返回前完成处理,再返回修改后的字典。
内容的提问来源于stack exchange,提问作者electromecca
相关产品推荐
相关产品推荐

