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

Bug: converting objects to a Bool in debug response #2381

Closed
1 of 4 tasks
geeshta opened this issue Sep 28, 2023 · 1 comment · Fixed by #2384
Closed
1 of 4 tasks

Bug: converting objects to a Bool in debug response #2381

geeshta opened this issue Sep 28, 2023 · 1 comment · Fixed by #2384
Labels
Bug 🐛 This is something that is not working as expected

Comments

@geeshta
Copy link
Sponsor Contributor

geeshta commented Sep 28, 2023

Description

The function litestar.middleware.exceptions._debug_response.get_symbol_name on line 51:

instance_or_cls = locals_dict.get("self") or locals_dict.get("cls")

The use of or operator calls the __bool__ function of the objects mapped to the self or cls keys. This causes problems when the object cannot be converted to bool which is unfortunately the case when using sqlalchemy, because it raises a TypeError for some of its classes (see here). The problem being that instead of the original DB error, the TypeError is propagated and the web exception renderer doesn't work for this case.

URL to code causing the issue

No response

MCVE

from litestar import Litestar, get
from litestar.contrib.sqlalchemy.base import BigIntBase
from litestar.contrib.sqlalchemy.plugins import (
    AsyncSessionConfig,
    SQLAlchemyAsyncConfig,
    SQLAlchemyInitPlugin,
)
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, mapped_column


class Name(BigIntBase):
    name: Mapped[str] = mapped_column(unique=True)


@get("/")
async def add_row(db_session: AsyncSession) -> dict:
    async with db_session.begin():
        new_name = Name(name="taken")
        db_session.add(new_name)

    return {"status": "ok"}


sqlalchemy_config = SQLAlchemyAsyncConfig(
    connection_string="sqlite+aiosqlite:///test.sqlite3",
    session_config=AsyncSessionConfig(expire_on_commit=False),
)
sqlalchemy_plugin = SQLAlchemyInitPlugin(config=sqlalchemy_config)


async def on_startup() -> None:
    """Initializes the database."""
    async with sqlalchemy_config.get_engine().begin() as conn:
        await conn.run_sync(BigIntBase.metadata.create_all)


app = Litestar(
    route_handlers=[add_row], plugins=[sqlalchemy_plugin], on_startup=[on_startup]
)

# Run "get /" twice - first call creates the entry, second one causes the error.

Steps to reproduce

1. Run the MCVE app (requires `aiosqlite` to be installed) with `--debug`
2. Navigate to "/" for the first time which creates the db row
3. Navigate to "/" for the second time to cause an IntegrityError
4. A `TypeError` is raised and propagated instead of the original DB error
5. The web debug exception renderer doesn't work

Screenshots

No response

Logs

[SQL: INSERT INTO name (name) VALUES (?)]
[parameters: ('taken',)]
(Background on this error at: https://sqlalche.me/e/20/gkpj)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 191, in __call__
    await self.app(scope, receive, send)
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 205, in __call__
    await self.handle_request_exception(
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 234, in handle_request_exception
    response = exception_handler(request, exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 270, in default_http_exception_handler
    return create_debug_response(request=request, exc=exc)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 184, in create_debug_response
    content: Any = create_html_response_content(exc=exc, request=request)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 137, in create_html_response_content
    exception_data: list[str] = [create_exception_html(exc, line_limit)]
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 122, in create_exception_html
    result = [create_frame_html(frame=frame, collapsed=idx > 0) for idx, frame in enumerate(reversed(frames))]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 122, in <listcomp>
    result = [create_frame_html(frame=frame, collapsed=idx > 0) for idx, frame in enumerate(reversed(frames))]
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 104, in create_frame_html
    "symbol_name": escape(get_symbol_name(frame)),
                          ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 51, in get_symbol_name
    instance_or_cls = locals_dict.get("self") or locals_dict.get("cls")
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 749, in __bool__
    raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 191, in __call__
    await self.app(scope, receive, send)
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/_asgi/asgi_router.py", line 84, in __call__
    await asgi_app(scope, receive, send)
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 205, in __call__
    await self.handle_request_exception(
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 234, in handle_request_exception
    response = exception_handler(request, exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 270, in default_http_exception_handler
    return create_debug_response(request=request, exc=exc)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 184, in create_debug_response
    content: Any = create_html_response_content(exc=exc, request=request)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 137, in create_html_response_content
    exception_data: list[str] = [create_exception_html(exc, line_limit)]
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 122, in create_exception_html
    result = [create_frame_html(frame=frame, collapsed=idx > 0) for idx, frame in enumerate(reversed(frames))]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 122, in <listcomp>
    result = [create_frame_html(frame=frame, collapsed=idx > 0) for idx, frame in enumerate(reversed(frames))]
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 104, in create_frame_html
    "symbol_name": escape(get_symbol_name(frame)),
                          ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 51, in get_symbol_name
    instance_or_cls = locals_dict.get("self") or locals_dict.get("cls")
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 749, in __bool__
    raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/app.py", line 517, in __call__
    await self.asgi_handler(scope, receive, self._wrap_send(send=send, scope=scope))  # type: ignore[arg-type]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 205, in __call__
    await self.handle_request_exception(
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 234, in handle_request_exception
    response = exception_handler(request, exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/middleware.py", line 270, in default_http_exception_handler
    return create_debug_response(request=request, exc=exc)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 184, in create_debug_response
    content: Any = create_html_response_content(exc=exc, request=request)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 137, in create_html_response_content
    exception_data: list[str] = [create_exception_html(exc, line_limit)]
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 122, in create_exception_html
    result = [create_frame_html(frame=frame, collapsed=idx > 0) for idx, frame in enumerate(reversed(frames))]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 122, in <listcomp>
    result = [create_frame_html(frame=frame, collapsed=idx > 0) for idx, frame in enumerate(reversed(frames))]
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 104, in create_frame_html
    "symbol_name": escape(get_symbol_name(frame)),
                          ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/litestar/middleware/exceptions/_debug_response.py", line 51, in get_symbol_name
    instance_or_cls = locals_dict.get("self") or locals_dict.get("cls")
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/geeshta/prog/litestar/bugs/.venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 749, in __bool__
    raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined
INFO:     127.0.0.1:48748 - "GET / HTTP/1.1" 500 Internal Server Error

Litestar Version

2.1.1

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Funding

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
Fund with Polar
@geeshta geeshta added Bug 🐛 This is something that is not working as expected Triage Required 🏥 This requires triage labels Sep 28, 2023
@geeshta geeshta changed the title Bug: converting objects to a Bool during debug Bug: converting objects to a Bool in debug response Sep 28, 2023
@peterschutt peterschutt removed the Triage Required 🏥 This requires triage label Sep 29, 2023
@peterschutt
Copy link
Contributor

Thanks for the good MCVE!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug 🐛 This is something that is not working as expected
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants