{"record":{"id":"a23beceac30afaef","repo":"arduino/Arduino","slug":"cannot-encode-objects-that-are-not-2-tuples","errorCode":null,"errorMessage":"cannot encode objects that are not 2-tuples","messagePattern":"cannot encode objects that are not 2-tuples","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"arduino-core/src/processing/app/i18n/python/requests/utils.py","lineNumber":113,"sourceCode":"def from_key_val_list(value):\n    \"\"\"Take an object and test to see if it can be represented as a\n    dictionary. Unless it can not be represented as such, return an\n    OrderedDict, e.g.,\n\n    ::\n\n        >>> from_key_val_list([('key', 'val')])\n        OrderedDict([('key', 'val')])\n        >>> from_key_val_list('string')\n        ValueError: need more than 1 value to unpack\n        >>> from_key_val_list({'key': 'val'})\n        OrderedDict([('key', 'val')])\n    \"\"\"\n    if value is None:\n        return None\n\n    if isinstance(value, (str, bytes, bool, int)):\n        raise ValueError('cannot encode objects that are not 2-tuples')\n\n    return OrderedDict(value)\n\n\ndef to_key_val_list(value):\n    \"\"\"Take an object and test to see if it can be represented as a\n    dictionary. If it can be, return a list of tuples, e.g.,\n\n    ::\n\n        >>> to_key_val_list([('key', 'val')])\n        [('key', 'val')]\n        >>> to_key_val_list({'key': 'val'})\n        [('key', 'val')]\n        >>> to_key_val_list('string')\n        ValueError: cannot encode objects that are not 2-tuples.\n    \"\"\"\n    if value is None:","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/arduino/Arduino/blob/a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee/arduino-core/src/processing/app/i18n/python/requests/utils.py#L95-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a dict or list of 2-tuples: params={'q': 'x'} or data=[('k','v')].","If you meant a raw query string, use the URL itself ('...?q=x') rather than params.","Wrap scalars appropriately: data={'value': 5}, not data=5.","Use to_key_val_list/from_key_val_list defensively in your own code with a try/except ValueError."],"exampleFix":"// before\nrequests.get(url, params='q=test')  # ValueError\n// after\nrequests.get(url, params={'q': 'test'})","handlingStrategy":"validation","validationCode":"def coerce_params(v):\n    if v is None or isinstance(v, (dict, list, tuple)):\n        return v\n    raise ValueError('params/data must be a dict or list of 2-tuples, got %r' % (v,))\nparams = coerce_params(raw_params)","typeGuard":"from collections.abc import Mapping\ndef is_key_val(v) -> bool:\n    if isinstance(v, (str, bytes, bool, int)):\n        return False\n    if isinstance(v, Mapping):\n        return True\n    return isinstance(v, (list, tuple)) and all(isinstance(t, (list, tuple)) and len(t) == 2 for t in v)","tryCatchPattern":"try:\n    resp = requests.get(url, params=p)\nexcept ValueError as e:\n    if 'not 2-tuples' in str(e):\n        raise TypeError('params must be dict or list of 2-tuples, got %s' % type(p).__name__) from e\n    raise","preventionTips":["Always pass dicts (or 2-tuple lists) to params/data/headers.","Watch for scalars reaching params via variables that also hold query strings.","Put raw query strings in the URL itself, not in params.","Validate request-building inputs in wrapper layers."],"tags":["requests","python","api-misuse","encoding"],"backgroundTag":"invalid-argument-value","analyzedSha":"a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee","analyzedAt":"2026-09-06T10:13:38.901Z","contentChangedAt":"2026-09-06T10:13:38.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}