fastapi icon indicating copy to clipboard operation
fastapi copied to clipboard

fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'starlette.responses.JSONResponse'> is a valid pydantic field type

Open zadigus opened this issue 2 years ago • 14 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the FastAPI documentation, with the integrated search.
  • [X] I already searched in Google "How to X in FastAPI" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to FastAPI but to Pydantic.
  • [X] I already checked if it is not related to FastAPI but to Swagger UI.
  • [X] I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • [X] I commit to help with one of those options 👆

Example Code

import logging

from fastapi import APIRouter
from fastapi.responses import JSONResponse

liveness = True

router = APIRouter()


@router.get(
    "/livez",
    summary="Liveness probe",
    description="Returns 200 if the service is alive",
)
async def get_liveness() -> JSONResponse:
    logging.debug("GET /livez")
    if liveness:
        return JSONResponse(status_code=200, content={"status": "ok"})
    else:
        return JSONResponse(status_code=500, content={"status": "not ok"})

Description

With version 0.88.0, my unit tests run fine, I get no error. With version 0.89.0, I get the following error:

/root/.pyenv/versions/3.8/lib/python3.8/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1014: in _gcd_import
    ???
<frozen importlib._bootstrap>:991: in _find_and_load
    ???
<frozen importlib._bootstrap>:975: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:671: in _load_unlocked
    ???
/root/.pyenv/versions/3.8/lib/python3.8/site-packages/_pytest/assertion/rewrite.py:168: in exec_module
    exec(co, module.__dict__)
tests/models/conftest.py:7: in <module>
    from my_sample_lib.main import app
my_sample_lib/main.py:10: in <module>
    from my_sample_lib.health.router import router as health_router
my_sample_lib/health/router.py:24: in <module>
    async def get_liveness() -> JSONResponse:
/root/.pyenv/versions/3.8/lib/python3.8/site-packages/fastapi/routing.py:633: in decorator
    self.add_api_route(
/root/.pyenv/versions/3.8/lib/python3.8/site-packages/fastapi/routing.py:572: in add_api_route
    route = route_class(
/root/.pyenv/versions/3.8/lib/python3.8/site-packages/fastapi/routing.py:400: in __init__
    self.response_field = create_response_field(
/root/.pyenv/versions/3.8/lib/python3.8/site-packages/fastapi/utils.py:90: in create_response_field
    raise fastapi.exceptions.FastAPIError(
E   fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'starlette.responses.JSONResponse'> is a valid pydantic field type

The only way I found to get rid of the error is to remove the type hint, which I don't really want. Also, I tried to follow the guidelines provided in your documentation without success.

Interestingly, the whole thing works fine (with the type hint and fastapi 0.89.0) under Windows 10. Under Ubuntu 22.10, it doesn't work at all (i.e. it provides the above message).

Operating System

Linux

Operating System Details

Under Windows 10, it works like a charm. Under Ubuntu 22.10, it fails with the provided error above.

FastAPI Version

0.89.0

Python Version

3.8.12

Additional Context

It is also failing with python 3.9, and 3.10.

zadigus avatar Jan 09 '23 11:01 zadigus

I encountered the same error with response classes

@zadigus You can specify response_model manually but I'm not sure if that's correct here 🤔

ThirVondukr avatar Jan 09 '23 12:01 ThirVondukr

pydantic does not recognize JSONReponse as being a valid field type, pydantic documentation says to add arbitrary_types_allowed in the Config to allow for arbitrary user types: (https://docs.pydantic.dev/usage/model_config/)

whether to allow arbitrary user types for fields (they are validated simply by checking if the value is an instance of the type). If False, RuntimeError will be raised on model declaration (default: False). See an example in Field Types.

The issue happens in fastapi.utils.create_response_field which calls pydantic.fields.ModelField (partially), it passes down model_config=pydantic.config.BaseConfig as a default value. Perhaps fastapi needs to add a way to pass custom config class when constructing the APIRoute to be passed down to create_response_field

class MyConfig:
    arbitrary_types_allowed = True

moadennagi avatar Jan 09 '23 12:01 moadennagi

pydantic does not recognize JSONReponse as being a valid field type, pydantic documentation says to add arbitrary_types_allowed in the Config to allow for arbitrary user types: (https://docs.pydantic.dev/usage/model_config/)

whether to allow arbitrary user types for fields (they are validated simply by checking if the value is an instance of the type). If False, RuntimeError will be raised on model declaration (default: False). See an example in Field Types.

The issue happens in fastapi.utils.create_response_field which calls pydantic.fields.ModelField (partially), it passes down model_config=pydantic.config.BaseConfig as a default value. Perhaps fastapi needs to add a way to pass custom config class when constructing the APIRoute to be passed down to create_response_field

class MyConfig:
    arbitrary_types_allowed = True

I think adding arbitrary_types_allowed=True would only cause Response to be interpreted as

content: Any
status_code: int
headers: ...
...

(As in Response.__init__), and what would be preferred is either fastapi recognizing Response subclasses or mentioning it in documentation and recommending a workaround (for example passing response_model=None explicitly)

ThirVondukr avatar Jan 09 '23 14:01 ThirVondukr

Same issue here, it is only checking for instances of pydantic.fields.ModelField, and ignoring instances of starlette.responses.Response, where comes from JSONResponse ...

It is also failing with python 3.9, and 3.10.

And 3.11

novitae avatar Jan 09 '23 14:01 novitae

Pretty sure it's a regression in release 0.89, since its only new feature deals with response_models: https://github.com/tiangolo/fastapi/pull/1436.

EDIT: Forgot to mention: my code worked with 0.88, but doesn't with 0.89, which is why I'm sure it's the culprit.

rassie avatar Jan 09 '23 15:01 rassie

Looks like a regression. Try with 0.88 if the issue exist?

iudeen avatar Jan 10 '23 01:01 iudeen

Yes, 0.88 works as expected.

rassie avatar Jan 10 '23 09:01 rassie

Small script to reproduce:

  • python 3.11
  • FastAPI 0.89
from fastapi import FastAPI, Response


app = FastAPI(debug=True)


@app.get("/plain-text")
def plain_text() -> Response:
    return Response(content="bla", media_type="text/plain")

Running this with python main.py will show this error.

Traceback (most recent call last):
  File "../fastapi-regression/main.py", line 7, in <module>
    @app.get("/plain-text")
     ^^^^^^^^^^^^^^^^^^^^^^
  File "../fastapi-regression/venv/lib/python3.11/site-packages/fastapi/routing.py", line 633, in decorator
    self.add_api_route(
  File "../fastapi-regression/venv/lib/python3.11/site-packages/fastapi/routing.py", line 572, in add_api_route
    route = route_class(
            ^^^^^^^^^^^^
  File "../fastapi-regression/venv/lib/python3.11/site-packages/fastapi/routing.py", line 400, in __init__
    self.response_field = create_response_field(
                          ^^^^^^^^^^^^^^^^^^^^^^
  File "../fastapi-regression/venv/lib/python3.11/site-packages/fastapi/utils.py", line 90, in create_response_field
    raise fastapi.exceptions.FastAPIError(
fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'starlette.responses.Response'> is a valid pydantic field type

hofrob avatar Jan 10 '23 09:01 hofrob

@hofrob with a test case so small, you'd have to wonder why the tests haven't catched this before release.

rassie avatar Jan 10 '23 09:01 rassie

This issue should be fixed by https://github.com/tiangolo/fastapi/pull/5855

ThirVondukr avatar Jan 10 '23 09:01 ThirVondukr

@hofrob with a test case so small, you'd have to wonder why the tests haven't catched this before release.

I guess we're all invited to add tests and fixes to this project. :shrug:

hofrob avatar Jan 10 '23 09:01 hofrob

This issue should be fixed by #5855

The pr sets response_model=None for Response subclasses, I wonder if there is way to support subclasses of Response

moadennagi avatar Jan 10 '23 10:01 moadennagi

Thanks for the report and discussion everyone! :coffee:

The simple use case of a single Response class is now supported in FastAPI 0.89.1 (just release) :tada:

And for the other use cases where you want to have more complex type annotations (e.g. unions, other types), you can use response_model=None.

There's a lot of new docs about it here: https://fastapi.tiangolo.com/tutorial/response-model/#other-return-type-annotations

Also, this is sort of a duplicate of https://github.com/tiangolo/fastapi/issues/5857 (it's the same issue underneath).

tiangolo avatar Jan 10 '23 17:01 tiangolo

Fastapi version 0.89.1 solves the issue in my codebase.

zadigus avatar Jan 14 '23 07:01 zadigus

Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.

github-actions[bot] avatar Feb 06 '23 11:02 github-actions[bot]

I have the same issue To resolve this issue I found only one way:

  1. pip show fastapi: Version: 0.101.0
  2. pip uninstall fastapi
  3. Then I modified my requirements.txt from fastapi to fastapi==0.88
  4. pip install -r requirements.txt
  5. pip uninstall fastapi
  6. Then I modified my requirements.txt again from fastapi==0.88 to fastapi
  7. pip install -r requirements.txt

And now my server runs without error...

lendoo73 avatar Aug 09 '23 15:08 lendoo73

I think we should open a new issue, but I am also reproducing, using fastapi 0.103.1, and migrating from pydantic v1 to pydantic v2 (2.4.1, tried with 2.2.1 as well)

CharlesPerrotMinotHCHB avatar Sep 27 '23 02:09 CharlesPerrotMinotHCHB

I think we should open a new issue, but I am also reproducing, using fastapi 0.103.1, and migrating from pydantic v1 to pydantic v2 (2.4.1, tried with 2.2.1 as well)

Please create a discussion. This issue was solved.

Kludex avatar Sep 27 '23 12:09 Kludex