aio-libs/aiohttp · error · ValueError

Multipart field missing name.

Error message

Multipart field missing name.

What it means

Raised as ValueError by BaseRequest.post() (aiohttp/web_request.py:749) while iterating multipart form fields: a BodyPartReader field whose Content-Disposition has no 'name' parameter. The multipart/form-data spec (RFC 7578) requires each part to declare a name; without it aiohttp cannot key the field in the returned MultiDict, so it refuses to silently produce a nameless entry.

Source

Thrown at aiohttp/web_request.py:749

            "application/x-www-form-urlencoded",
            "multipart/form-data",
        ):
            self._post = MultiDictProxy(MultiDict())
            return self._post

        out: MultiDict[str | bytes | FileField] = MultiDict()

        if content_type == "multipart/form-data":
            multipart = await self.multipart()
            max_size = self._client_max_size

            size = 0
            while (field := await multipart.next()) is not None:
                field_ct = field.headers.get(hdrs.CONTENT_TYPE)

                if isinstance(field, BodyPartReader):
                    if field.name is None:
                        raise ValueError("Multipart field missing name.")

                    # Note that according to RFC 7578, the Content-Type header
                    # is optional, even for files, so we can't assume it's
                    # present.
                    # https://tools.ietf.org/html/rfc7578#section-4.4
                    if field.filename:
                        # store file in temp file
                        tmp = await self._loop.run_in_executor(
                            None, tempfile.TemporaryFile
                        )
                        while chunk := await field.read_chunk(size=DEFAULT_CHUNK_SIZE):
                            async for decoded_chunk in field.decode_iter(chunk):
                                await self._loop.run_in_executor(
                                    None, tmp.write, decoded_chunk
                                )
                                size += len(decoded_chunk)
                                if 0 < max_size < size:
                                    await self._loop.run_in_executor(None, tmp.close)

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Fix the client to send Content-Disposition: form-data; name="field" for every part (curl -F 'field=@file.txt').
  2. If you must tolerate nameless parts, parse with request.multipart() directly and decide how to key them yourself.
  3. Wrap await request.post() in try/except ValueError and return HTTPBadRequest with guidance.

Example fix

// before
async def handler(request):
    form = await request.post()  # ValueError on nameless part

# after
try:
    form = await request.post()
except ValueError:
    raise web.HTTPBadRequest(text="multipart fields need a name")
Defensive patterns

Strategy: try-catch

Type guard

def all_parts_named(multipart_reader) -> bool:
    # naive: cannot check without consuming; rely on try/except
    return True

Try / catch

try:
    form = await request.post()
except ValueError:
    raise web.HTTPBadRequest(text="multipart fields need a name")

Prevention

When it happens

Trigger: await request.post() on a multipart/form-data body that contains a part with Content-Disposition: form-data; filename=foo.txt (no name= attribute). Common with hand-rolled clients, some native HTTP libraries, or proxies that strip fields.

Common situations: Custom file-upload clients that omit name; curl commands with -F '=@file.txt' (the empty field name); legacy desktop/mobile uploaders; testing tools that build multipart bodies manually.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/1eeaeb25f28acf00.json. Report an issue: GitHub.