If the return type of a route has more than one field which is generic on one or two (possibly more?) types the expected serialization does not occur.
TL;DR
Current behavior: Serialization Fails for all routes except route-0
Expected behavior: Serialization Success
No response
from dataclasses import dataclass
from typing import Generic, TypeVar
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from litestar import Response, get
from litestar.contrib.sqlalchemy.plugins import SQLAlchemySerializationPlugin
from litestar.testing import create_test_client
class Base(DeclarativeBase):
pass
class SomeTable(Base):
__tablename__ = "something"
id: Mapped[int] = mapped_column(primary_key=True)
col: Mapped[str]
T = TypeVar("T")
U = TypeVar("U")
@dataclass
class GenericOnOne(Generic[T]):
val_1: list[T]
@dataclass
class GenericOnTwo(Generic[T, U]):
val_1: list[T]
val_2: list[U]
@dataclass
class GenericOnOneButTwoFields(Generic[T]):
val_1: list[T]
val_2: list[T]
t = [SomeTable(id=1, col="Hello, World!")]
@get("route-0")
async def route_0() -> GenericOnOne[SomeTable]:
# nothing wrong here, just to show it works
return GenericOnOne(val_1=t)
@get("route-1")
async def route_1() -> GenericOnTwo[SomeTable, SomeTable]:
# fails to serialize if it has two fields generic on different types
return GenericOnTwo(val_1=t, val_2=t)
@get("route-2")
async def route_2() -> GenericOnOneButTwoFields[SomeTable]:
# fails to serialize if has two fields generic on the same types
return GenericOnOneButTwoFields(val_1=t, val_2=t)
@get("route-3")
async def route_3() -> Response[GenericOnOne[SomeTable]]:
# fails to serialize when wrapped with another Generic
return Response(GenericOnOne(val_1=t))
with create_test_client(
[route_0, route_1, route_2, route_3], plugins=[SQLAlchemySerializationPlugin()]
) as client:
response_0 = client.get("route-0")
assert response_0.status_code == 200
response_1 = client.get("route-1")
assert response_1.status_code == 500
response_2 = client.get("route-2")
assert response_2.status_code == 500
response_3 = client.get("route-3")
assert response_3.status_code == 500
Run the code
"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"
Traceback (most recent call last):
File "litestar/litestar/serialization/msgspec_hooks.py", line 162, in encode_json
return msgspec.json.encode(value, enc_hook=serializer) if serializer else _msgspec_json_encoder.encode(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/serialization/msgspec_hooks.py", line 92, in default_serializer
raise TypeError(f"Unsupported type: {type(value)!r}")
TypeError: Unsupported type: <class '__main__.SomeTable'>
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "litestar/litestar/middleware/_internal/exceptions/middleware.py", line 158, in __call__
await self.app(scope, receive, capture_response_started)
File "litestar/litestar/_asgi/asgi_router.py", line 99, in __call__
await asgi_app(scope, receive, send)
File "litestar/litestar/routes/http.py", line 80, in handle
response = await self._get_response_for_request(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/routes/http.py", line 132, in _get_response_for_request
return await self._call_handler_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/routes/http.py", line 156, in _call_handler_function
response: ASGIApp = await route_handler.to_response(app=scope["app"], data=response_data, request=request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/handlers/http_handlers/base.py", line 557, in to_response
return await response_handler(app=app, data=data, request=request) # type: ignore[call-arg]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/handlers/http_handlers/_utils.py", line 79, in handler
return response.to_asgi_response(app=None, request=request, headers=normalize_headers(headers), cookies=cookies) # pyright: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/response/base.py", line 451, in to_asgi_response
body=self.render(self.content, media_type, get_serializer(type_encoders)),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/response/base.py", line 392, in render
return encode_json(content, enc_hook)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "litestar/litestar/serialization/msgspec_hooks.py", line 164, in encode_json
raise SerializationException(str(msgspec_error)) from msgspec_error
litestar.exceptions.base_exceptions.SerializationException: Unsupported type: <class '__main__.SomeTable'>
84f51c8 (main as of issue creation)
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too