Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeyError issue when initializing FastAPI app #60

Open
fsecada01 opened this issue Jan 20, 2025 · 0 comments
Open

KeyError issue when initializing FastAPI app #60

fsecada01 opened this issue Jan 20, 2025 · 0 comments

Comments

@fsecada01
Copy link

Expected Behavior

The Debug Toolbar should initialize without errors and should render the HTML/JS content of the toolbar, with it docked to the right of the screen and collapsible.

Current Behavior

The application renders a 500 Error when the FastAPI app is up via Uvicorn.

Possible Solution

The KeyError is due to a 3rd party module dependency having incomplete/missing Metadata, particularly the name value for the application.

The best solution for these edge cases is to implement the get function for accessing a value via a key name instead of using square brackets. This will allow the empty value to pass through instead of raising the error.

Steps to reproduce

It is difficult to ascertain the precise conditions for when this error will arise (since the module name is not provided due to missing metadata), but the particular case may be when building comprehensive applications with larger requirements. My existing core requirements are below, as captured in a .in file.

aiofiles
aiomysql
celery
fastapi
fastapi-restful
fastcrud
flower
greenlet
gunicorn; platform_system != 'Windows'
httpx
httpx[socks]
httpx-html
html5lib
hypercorn; platform_system == 'Windows'
itsdangerous
jinjax
loguru
lxml
lxml[html_clean]
python-dateutil
python-decouple
python-slugify
psycopg
pydantic-ai[examples]
pytz
redis
simplejson
sqlalchemy_mixins
sqlmodel
sqlmodel-crud-utilities @ git+https://github.com/fsecada01/[email protected]
typing-inspect
uvicorn
xmljson
xmltodict

The steps are below.

  1. Create a virtual environment (e.g.: uv venv .venv)
  2. Install requirements (e.g.: uv pip sync requirements.txt)
  3. Instantiate a minimal build FastAPI build
  4. Include DebugToolbarMiddle in the app via add_middleware function for app instance
  5. Run python -m app.py if the main app file includes if __name__ == '__main__': line or run uvicorn app:app from CLI

Content

Running:

  • Windows 11
  • Python 3.13
  • UV

Detailed Description

The following error log appears when attempting to initialize the application.

INFO:     127.0.0.1:16788 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
  + Exception Group Traceback (most recent call last):
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\base.py", line 187, in __call__
  |     response = await self.dispatch_func(request, call_next)
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\middleware.py", line 84, in dispatch
  |     await toolbar.record_stats(response)
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\toolbar.py", line 91, in record_stats
  |     async with create_task_group() as tg:
  |                ~~~~~~~~~~~~~~~~~^^
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\anyio\_backends\_asyncio.py", line 767, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     )
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 403, in run_asgi
    |     result = await app(  # type: ignore[func-returns-value]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         self.scope, self.receive, self.send
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     )
    |     ^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
    |     return await self.app(scope, receive, send)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
    |     await super().__call__(scope, receive, send)
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\applications.py", line 113, in __call__
    |     await self.middleware_stack(scope, receive, send)
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\errors.py", line 187, in __call__
    |     raise exc
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\errors.py", line 165, in __call__
    |     await self.app(scope, receive, _send)
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\base.py", line 185, in __call__
    |     with collapse_excgroups():
    |          ~~~~~~~~~~~~~~~~~~^^
    |   File "C:\Python313\Lib\contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\_utils.py", line 82, in collapse_excgroups
    |     raise exc
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\__init__.py", line 88, in record_stats
    |     stats = await self.generate_stats(request, response)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\versions.py", line 26, in generate_stats
    |     packages = sorted(
    |         metadata.distributions(),
    |         key=lambda dist: dist.metadata["name"].lower(),
    |     )
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\versions.py", line 28, in <lambda>
    |     key=lambda dist: dist.metadata["name"].lower(),
    |                      ~~~~~~~~~~~~~^^^^^^^^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\importlib_metadata\_adapters.py", line 54, in __getitem__
    |     raise KeyError(item)
    | KeyError: 'name'
    +------------------------------------

During handling of the above exception, another exception occurred:

  + Exception Group Traceback (most recent call last):
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\_utils.py", line 76, in collapse_excgroups
  |     yield
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\base.py", line 186, in __call__
  |     async with anyio.create_task_group() as task_group:
  |                ~~~~~~~~~~~~~~~~~~~~~~~^^
  |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\anyio\_backends\_asyncio.py", line 767, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     )
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\base.py", line 187, in __call__
    |     response = await self.dispatch_func(request, call_next)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\middleware.py", line 84, in dispatch
    |     await toolbar.record_stats(response)
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\toolbar.py", line 91, in record_stats
    |     async with create_task_group() as tg:
    |                ~~~~~~~~~~~~~~~~~^^
    |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\anyio\_backends\_asyncio.py", line 767, in __aexit__
    |     raise BaseExceptionGroup(
    |         "unhandled errors in a TaskGroup", self._exceptions
    |     )
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 403, in run_asgi
      |     result = await app(  # type: ignore[func-returns-value]
      |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |         self.scope, self.receive, self.send
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |     )
      |     ^
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
      |     return await self.app(scope, receive, send)
      |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
      |     await super().__call__(scope, receive, send)
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\applications.py", line 113, in __call__
      |     await self.middleware_stack(scope, receive, send)
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\errors.py", line 187, in __call__
      |     raise exc
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\errors.py", line 165, in __call__
      |     await self.app(scope, receive, _send)
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\base.py", line 185, in __call__
      |     with collapse_excgroups():
      |          ~~~~~~~~~~~~~~~~~~^^
      |   File "C:\Python313\Lib\contextlib.py", line 162, in __exit__
      |     self.gen.throw(value)
      |     ~~~~~~~~~~~~~~^^^^^^^
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\_utils.py", line 82, in collapse_excgroups
      |     raise exc
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\__init__.py", line 88, in record_stats
      |     stats = await self.generate_stats(request, response)
      |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\versions.py", line 26, in generate_stats
      |     packages = sorted(
      |         metadata.distributions(),
      |         key=lambda dist: dist.metadata["name"].lower(),
      |     )
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\versions.py", line 28, in <lambda>
      |     key=lambda dist: dist.metadata["name"].lower(),
      |                      ~~~~~~~~~~~~~^^^^^^^^
      |   File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\importlib_metadata\_adapters.py", line 54, in __getitem__
      |     raise KeyError(item)
      | KeyError: 'name'
      +------------------------------------

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 403, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        self.scope, self.receive, self.send
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\errors.py", line 187, in __call__
    raise exc
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\errors.py", line 165, in __call__
    await self.app(scope, receive, _send)
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\middleware\base.py", line 185, in __call__
    with collapse_excgroups():
         ~~~~~~~~~~~~~~~~~~^^
  File "C:\Python313\Lib\contextlib.py", line 162, in __exit__
    self.gen.throw(value)
    ~~~~~~~~~~~~~~^^^^^^^
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\starlette\_utils.py", line 82, in collapse_excgroups
    raise exc
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\__init__.py", line 88, in record_stats
    stats = await self.generate_stats(request, response)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\versions.py", line 26, in generate_stats
    packages = sorted(
        metadata.distributions(),
        key=lambda dist: dist.metadata["name"].lower(),
    )
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\debug_toolbar\panels\versions.py", line 28, in <lambda>
    key=lambda dist: dist.metadata["name"].lower(),
                     ~~~~~~~~~~~~~^^^^^^^^
  File "C:\dev\python\interview_eval_project\highmark_agentic_ai\.venv\Lib\site-packages\importlib_metadata\_adapters.py", line 54, in __getitem__
    raise KeyError(item)
KeyError: 'name'

Possible Implementation

The below code seems to fix this issue:

    async def generate_stats(self, request: Request, response: Response) -> Stats:
        dists = {d.metadata.get("name", None): d for d in
                 metadata.distributions()}
        packages = sorted(
            dists,
            key=lambda dist: dist.lower() if dist else "",
        )
        return {"packages": packages}
fsecada01 added a commit to fsecada01/fastapi-debug-toolbar that referenced this issue Jan 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant