huggingface/smolagents · error · InterpreterError

Cannot unpack non-tuple value

Error message

Cannot unpack non-tuple value

What it means

When unpacking into a tuple target (a, b = value), set_value requires value to be a tuple; iterables that are not str/bytes get converted, but non-iterables raise InterpreterError('Cannot unpack non-tuple value'). Strings and bytes are deliberately rejected to avoid surprising per-character unpacking.

Source

Thrown at src/smolagents/local_python_executor.py:811

def set_value(
    target: ast.AST,
    value: Any,
    state: dict[str, Any],
    static_tools: dict[str, Callable],
    custom_tools: dict[str, Callable],
    authorized_imports: list[str],
) -> None:
    if isinstance(target, ast.Name):
        if target.id in static_tools:
            raise InterpreterError(f"Cannot assign to name '{target.id}': doing this would erase the existing tool!")
        state[target.id] = value
    elif isinstance(target, ast.Tuple):
        if not isinstance(value, tuple):
            if hasattr(value, "__iter__") and not isinstance(value, (str, bytes)):
                value = tuple(value)
            else:
                raise InterpreterError("Cannot unpack non-tuple value")
        if len(target.elts) != len(value):
            raise InterpreterError("Cannot unpack tuple of wrong size")
        for i, elem in enumerate(target.elts):
            set_value(elem, value[i], state, static_tools, custom_tools, authorized_imports)
    elif isinstance(target, ast.Subscript):
        obj = evaluate_ast(target.value, state, static_tools, custom_tools, authorized_imports)
        key = evaluate_ast(target.slice, state, static_tools, custom_tools, authorized_imports)
        obj[key] = value
    elif isinstance(target, ast.Attribute):
        obj = evaluate_ast(target.value, state, static_tools, custom_tools, authorized_imports)
        setattr(obj, target.attr, value)


def evaluate_call(
    call: ast.Call,
    state: dict[str, Any],
    static_tools: dict[str, Callable],
    custom_tools: dict[str, Callable],

View on GitHub (pinned to 30bb116109)

Solutions

  1. Check/guard the shape before unpacking: `if isinstance(v, (tuple, list)) and len(v) == 2: a, b = v`
  2. Convert first: `a, b = tuple(v)` or `a, b = list(v)` when v is a non-str iterable
  3. Fix the data source so it genuinely returns the expected tuple

Example fix

# before
code = "a, b = '12'"

# after
code = "a, b = (1, 2)"
Defensive patterns

Strategy: type-guard

Validate before calling

def can_unpack(v, n) -> bool:
    return isinstance(v, tuple) and len(v) == n or (hasattr(v, '__iter__') and not isinstance(v, (str, bytes)) and len(list(v)) == n)

Type guard

def is_unpackable(v) -> bool:
    return isinstance(v, tuple) or (hasattr(v, '__iter__') and not isinstance(v, (str, bytes)))

Try / catch

from smolagents.local_python_executor import InterpreterError
try:
    evaluate_python(code)
except InterpreterError as e:
    if 'Cannot unpack non-tuple value' in str(e):
        code = guard_unpack_sites(code)  # add isinstance checks before a, b = v

Prevention

When it happens

Trigger: `a, b = 5`, `a, b = None`, `a, b = 'xy'`, or unpacking an object with no __iter__ in executed code; also fires for for-loop targets and comprehension unpacking since they share set_value.

Common situations: Tool returns None or a scalar where the model expected a pair; unpacking a string the model assumed was a tuple; unpacking a dict yields keys confusion; LLM pattern-matches tuple syntax onto non-tuple data.

Related errors


AI-assisted analysis of huggingface/smolagents@30bb116109 (2026-08-28). Data as JSON: /api/errors/e3adde36e426c821. Report an issue: GitHub.