arduino/Arduino · error · ValueError

cannot encode objects that are not 2-tuples

Error message

cannot encode objects that are not 2-tuples

What it means

utils.from_key_val_list converts request data into an OrderedDict. It rejects scalar values (str, bytes, bool, int) because they cannot be interpreted as key/value pairs, raising ValueError so users get a clear message instead of a cryptic failure later during URL-encoding.

Source

Thrown at arduino-core/src/processing/app/i18n/python/requests/utils.py:113

def from_key_val_list(value):
    """Take an object and test to see if it can be represented as a
    dictionary. Unless it can not be represented as such, return an
    OrderedDict, e.g.,

    ::

        >>> from_key_val_list([('key', 'val')])
        OrderedDict([('key', 'val')])
        >>> from_key_val_list('string')
        ValueError: need more than 1 value to unpack
        >>> from_key_val_list({'key': 'val'})
        OrderedDict([('key', 'val')])
    """
    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)


def to_key_val_list(value):
    """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.,

    ::

        >>> to_key_val_list([('key', 'val')])
        [('key', 'val')]
        >>> to_key_val_list({'key': 'val'})
        [('key', 'val')]
        >>> to_key_val_list('string')
        ValueError: cannot encode objects that are not 2-tuples.
    """
    if value is None:

View on GitHub (pinned to a0df6e0e83)

Solutions

  1. Pass a dict or list of 2-tuples: params={'q': 'x'} or data=[('k','v')].
  2. If you meant a raw query string, use the URL itself ('...?q=x') rather than params.
  3. Wrap scalars appropriately: data={'value': 5}, not data=5.
  4. Use to_key_val_list/from_key_val_list defensively in your own code with a try/except ValueError.

Example fix

// before
requests.get(url, params='q=test')  # ValueError
// after
requests.get(url, params={'q': 'test'})
Defensive patterns

Strategy: validation

Validate before calling

def coerce_params(v):
    if v is None or isinstance(v, (dict, list, tuple)):
        return v
    raise ValueError('params/data must be a dict or list of 2-tuples, got %r' % (v,))
params = coerce_params(raw_params)

Type guard

from collections.abc import Mapping
def is_key_val(v) -> bool:
    if isinstance(v, (str, bytes, bool, int)):
        return False
    if isinstance(v, Mapping):
        return True
    return isinstance(v, (list, tuple)) and all(isinstance(t, (list, tuple)) and len(t) == 2 for t in v)

Try / catch

try:
    resp = requests.get(url, params=p)
except ValueError as e:
    if 'not 2-tuples' in str(e):
        raise TypeError('params must be dict or list of 2-tuples, got %s' % type(p).__name__) from e
    raise

Prevention

When it happens

Trigger: Passing params='foo', data=5, headers=True, or similar scalar instead of a dict/list of 2-tuples to requests APIs (session.request, merge_environment_settings, merge_kwargs); passing a dict-like of non-2-tuples.

Common situations: Confusing params with a plain string query; accidentally passing a boolean/int (e.g. data=page_count); copy-paste where a variable holding a scalar is used where a dict was intended.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of arduino/Arduino@a0df6e0e83 (2026-09-06). Data as JSON: /api/errors/a23beceac30afaef. Report an issue: GitHub.