psf/requests · error · ValueError

cannot encode objects that are not 2-tuples

Error message

cannot encode objects that are not 2-tuples

What it means

Raised by from_key_val_list() when the input is a scalar type (str, bytes, bool, or int) that cannot be interpreted as an iterable of key-value pairs. This utility builds an OrderedDict from mappings or 2-tuple iterables. Scalar types are explicitly rejected because they would produce a confusing error inside OrderedDict().

Solutions

  1. Pass a dict or list of tuples instead of a scalar: from_key_val_list({'key': 'val'}).
  2. If you have a single string value, wrap it in a structure: from_key_val_list([('key', 'value')]).
  3. Check the type before calling: if not isinstance(value, (str, bytes, bool, int)).

Example fix

# before
from requests.utils import from_key_val_list
result = from_key_val_list('my string')  # ValueError

# after
result = from_key_val_list({'my': 'string'})
Defensive patterns

Strategy: type-guard

Validate before calling

if isinstance(value, (str, bytes, bool, int)):
    raise ValueError(f'Expected dict or iterable of tuples, got {type(value)}')
result = from_key_val_list(value)

Type guard

from collections.abc import Mapping, Iterable
def is_key_val_capable(v) -> bool:
    return v is None or isinstance(v, (Mapping,)) or (
        isinstance(v, Iterable) and not isinstance(v, (str, bytes))
    )

Prevention

When it happens

Trigger: Calling from_key_val_list('a string'), from_key_val_list(42), from_key_val_list(True), or from_key_val_list(b'bytes'); passing a scalar where a dict or list-of-tuples is expected.

Common situations: This function is used internally (e.g., in cookie and data encoding). Users typically hit it indirectly by passing a string where a dict is expected to params/data/cookies kwargs; or by calling this utility directly with wrong types.

Related errors


AI-assisted analysis of psf/requests@8068356288 (2026-08-11). Data as JSON: /api/errors/d97bc89b2dd6e20e. Report an issue: GitHub.

Appendix: source

Thrown at src/requests/utils.py:365

    ::

        >>> from_key_val_list([('key', 'val')])
        OrderedDict([('key', 'val')])
        >>> from_key_val_list('string')
        Traceback (most recent call last):
        ...
        ValueError: cannot encode objects that are not 2-tuples
        >>> from_key_val_list({'key': 'val'})
        OrderedDict([('key', 'val')])

    :rtype: OrderedDict
    """
    if value is None:
        return None

    if isinstance(value, (str, bytes, bool, int)):
        raise ValueError("cannot encode objects that are not 2-tuples")

    return OrderedDict(value)


@overload
def to_key_val_list(value: None) -> None: ...
@overload
def to_key_val_list(
    value: _t.SupportsItems[_KT, _VT] | Iterable[tuple[_KT, _VT]],
) -> list[tuple[_KT, _VT]]: ...
def to_key_val_list(
    value: _t.SupportsItems[_KT, _VT] | Iterable[tuple[_KT, _VT]] | None,
) -> list[tuple[_KT, _VT]] | None:
    """Take an object and test to see if it can be represented as a
    dictionary. If it can be, return a list of tuples, e.g.,

    ::

View on GitHub (pinned to 8068356288)