Skip to content

Documentation: Examples using dict[str, UploadFile] don't work as advertised #2940

@vkcku

Description

@vkcku

Description

A msgpsec validation error is raised when annotating as data: dict[str, UploadFile]. This is because what we actually give msgspec is list of UploadFiles, but they have to converted into a dictionary before that. Also, I wasn't able to find any tests for these (maybe I missed them) which may mean this has never worked :D

URL to code causing the issue

No response

MCVE

from __future__ import annotations

from litestar import post
from litestar.datastructures import UploadFile
from litestar.enums import RequestEncodingType
from litestar.params import Body
from litestar.status_codes import HTTP_201_CREATED
from litestar.testing.helpers import create_test_client


@post(path="/")
async def upload_files_object(
    data: dict[str, UploadFile] = Body(media_type=RequestEncodingType.MULTI_PART)
) -> list[str]:
    return list(data.keys())


with create_test_client([upload_files_object]) as client:
    files = [("files", ("filename", b"1")), ("files", ("another_filename", b"1"))]
    response = client.post("/", files=files)

    assert response.status_code == HTTP_201_CREATED
    assert response.json() == ["filename", "another_filename"]

Steps to reproduce

1. Run the MCVE

Screenshots

No response

Logs

Traceback (most recent call last):
  File "/home/guacs/open-source/litestar/litestar/_signature/model.py", line 93, in _deserializer
    return default_deserializer(target_type, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/serialization/msgspec_hooks.py", line 118, in default_deserializer
    raise TypeError(f"Unsupported type: {type(value)!r}")
TypeError: Unsupported type: <class 'list'>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/guacs/open-source/litestar/litestar/_signature/model.py", line 189, in parse_values_from_connection_kwargs
    return convert(kwargs, cls, strict=False, dec_hook=deserializer, str_keys=True).to_dict()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
msgspec.ValidationError: Unsupported type: <class 'list'> - at `$.data[...]`

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/guacs/open-source/litestar/litestar/middleware/exceptions/middleware.py", line 191, in __call__
    await self.app(scope, receive, send)
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 82, in handle
    response = await self._get_response_for_request(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 134, in _get_response_for_request
    return await self._call_handler_function(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 154, in _call_handler_function
    response_data, cleanup_group = await self._get_response_data(
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 193, in _get_response_data
    parsed_kwargs = route_handler.signature_model.parse_values_from_connection_kwargs(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/_signature/model.py", line 202, in parse_values_from_connection_kwargs
    raise cls._create_exception(messages=messages, connection=connection) from e
litestar.exceptions.http_exceptions.ValidationException: 400: Validation failed for POST http://testserver.local/
Traceback (most recent call last):
  File "/home/guacs/open-source/litestar/litestar/_signature/model.py", line 93, in _deserializer
    return default_deserializer(target_type, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/serialization/msgspec_hooks.py", line 118, in default_deserializer
    raise TypeError(f"Unsupported type: {type(value)!r}")
TypeError: Unsupported type: <class 'list'>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/guacs/open-source/litestar/litestar/_signature/model.py", line 189, in parse_values_from_connection_kwargs
    return convert(kwargs, cls, strict=False, dec_hook=deserializer, str_keys=True).to_dict()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
msgspec.ValidationError: Unsupported type: <class 'list'> - at `$.data[...]`

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/guacs/open-source/litestar/litestar/middleware/exceptions/middleware.py", line 191, in __call__
    await self.app(scope, receive, send)
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 82, in handle
    response = await self._get_response_for_request(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 134, in _get_response_for_request
    return await self._call_handler_function(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 154, in _call_handler_function
    response_data, cleanup_group = await self._get_response_data(
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/routes/http.py", line 193, in _get_response_data
    parsed_kwargs = route_handler.signature_model.parse_values_from_connection_kwargs(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/guacs/open-source/litestar/litestar/_signature/model.py", line 202, in parse_values_from_connection_kwargs
    raise cls._create_exception(messages=messages, connection=connection) from e
litestar.exceptions.http_exceptions.ValidationException: 400: Validation failed for POST http://testserver.local/

Litestar Version

Main

Platform

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Status

Closed

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions