encode/httpx · error · TypeError

Invalid type for value. Expected primitive type, got {type(v

Error message

Invalid type for value. Expected primitive type, got {type(value)}: {value!r}

What it means

Raised as `TypeError` by `DataField.__init__` when a multipart field `value` is not one of the allowed primitive types (`str`, `bytes`, `int`, `float`, or `None`). Multipart form values must serialize to bytes; arbitrary objects (lists, dicts, custom classes) cannot be sent as plain form fields and are rejected.

Source

Thrown at httpx/_multipart.py:81

    if b";" in content_type:
        for section in content_type.split(b";"):
            if section.strip().lower().startswith(b"boundary="):
                return section.strip()[len(b"boundary=") :].strip(b'"')
    return None


class DataField:
    """
    A single form field item, within a multipart form field.
    """

    def __init__(self, name: str, value: str | bytes | int | float | None) -> None:
        if not isinstance(name, str):
            raise TypeError(
                f"Invalid type for name. Expected str, got {type(name)}: {name!r}"
            )
        if value is not None and not isinstance(value, (str, bytes, int, float)):
            raise TypeError(
                "Invalid type for value. Expected primitive type,"
                f" got {type(value)}: {value!r}"
            )
        self.name = name
        self.value: str | bytes = (
            value if isinstance(value, bytes) else primitive_value_to_str(value)
        )

    def render_headers(self) -> bytes:
        if not hasattr(self, "_headers"):
            name = _format_form_param("name", self.name)
            self._headers = b"".join(
                [b"Content-Disposition: form-data; ", name, b"\r\n\r\n"]
            )

        return self._headers

    def render_data(self) -> bytes:

View on GitHub (pinned to b5addb64f0)

Solutions

  1. Send structured data as JSON: `client.post(url, json=payload)` instead of `data=payload`.
  2. If the API expects a stringified field, serialize first: `data={'opts': ','.join(opts)}` or `json.dumps(value)`.
  3. Flatten nested structures into multiple `key[]`-style field names if the server expects repeated form fields.
  4. Add a pre-flight type check on each value.

Example fix

// before
client.post(url, data={'filters': {'a': 1}})  # TypeError

// after
client.post(url, json={'filters': {'a': 1}})
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = (str, bytes, int, float, type(None))
def validate_form_values(data: dict) -> None:
    bad = {k: type(v).__name__ for k, v in data.items()
           if not isinstance(v, ALLOWED)}
    if bad:
        raise TypeError(f'non-primitive form values: {bad}')

Type guard

def form_values_are_primitive(data: dict) -> bool:
    return all(
        v is None or isinstance(v, (str, bytes, int, float))
        for v in data.values()
    )

Try / catch

try:
    client.post(url, data=payload)
except TypeError:
    # structured payload - send as JSON instead
    client.post(url, json=payload)

Prevention

When it happens

Trigger: Passing `data={'opt': ['a','b']}` or `data={'obj': some_object}` to `client.post(url, data=...)`; using a dict-of-dicts where each value is structured rather than scalar.

Common situations: Confusing form fields with JSON bodies — passing nested data to `data=` instead of `json=`; forgetting to `json.dumps` a list before putting it in a form field; serializing ORM objects naively.

Related errors


AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04). Data as JSON: /data/errors/f4ff5a851445cf94.json. Report an issue: GitHub.