huggingface/smolagents · error · InterpreterError

Object is not iterable

Error message

Object is not iterable

What it means

get_iterable is used by the executor's for-loop and comprehension handling to normalize the iterated object: lists pass through, objects with __iter__ are materialized via list(obj), and anything else raises InterpreterError('Object is not iterable'). It mirrors Python's TypeError 'not iterable' inside the sandbox.

Source

Thrown at src/smolagents/local_python_executor.py:329

                    result = future.result(timeout=timeout_seconds)
                    return result
                except FuturesTimeoutError:
                    raise ExecutionTimeoutError(
                        f"Code execution exceeded the maximum execution time of {timeout_seconds} seconds"
                    )

        return wrapper

    return decorator


def get_iterable(obj):
    if isinstance(obj, list):
        return obj
    elif hasattr(obj, "__iter__"):
        return list(obj)
    else:
        raise InterpreterError("Object is not iterable")


def fix_final_answer_code(code: str) -> str:
    """
    Sometimes an LLM can try to assign a variable to final_answer, which would break the final_answer() tool.
    This function fixes this behaviour by replacing variable assignments to final_answer with final_answer_variable,
    while preserving function calls to final_answer().
    """
    # First, find if there's a direct assignment to final_answer
    # Use word boundary and negative lookbehind to ensure it's not an object attribute
    assignment_pattern = r"(?<!\.)(?<!\w)\bfinal_answer\s*="
    if "final_answer(" not in code or not re.search(assignment_pattern, code):
        # If final_answer tool is not called in this blob, then doing the replacement is hazardous because it could false the model's memory for next steps.
        # Let's not modify the code and leave the subsequent assignment error happen.
        return code

    # Pattern for replacing variable assignments
    # Looks for 'final_answer' followed by '=' with optional whitespace

View on GitHub (pinned to 30bb116109)

Solutions

  1. Inspect/guard the value before iterating: `if hasattr(x, '__iter__')` or isinstance checks, and wrap scalars ([x])
  2. Fix the upstream expression so it produces the intended iterable (e.g. use range(n) instead of n)
  3. Handle None returns from tools with a default: `items = tool() or []`

Example fix

# before
code = "total = 0\nfor x in len([1,2,3]):\n    total += x"

# after
code = "total = 0\nfor x in [1,2,3]:\n    total += x"
Defensive patterns

Strategy: type-guard

Validate before calling

def ensure_iterable(v):
    if isinstance(v, (list, tuple)):
        return list(v)
    if hasattr(v, '__iter__'):
        return list(v)
    return [v]  # wrap scalars

Type guard

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

Try / catch

from smolagents.local_python_executor import InterpreterError
try:
    evaluate_python(code)
except InterpreterError as e:
    if 'not iterable' in str(e):
        code = fix_loop_target(code)  # wrap the iterated value in [..]

Prevention

When it happens

Trigger: Executed code iterates over an int, float, None, or a non-iterable object, e.g. `for x in 5:` or `for c in len(s):`, or a comprehension like `[i for i in 42]`.

Common situations: LLM assumes a tool returns a list when it returns a scalar or None; iterating a variable before it is assigned; iterating a dict-like result that is actually a JSON number; calling a function that returns None on error and looping over it.

Related errors


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