{"record":{"id":"89ce0264bfccffba","repo":"huggingface/smolagents","slug":"object-is-not-iterable","errorCode":null,"errorMessage":"Object is not iterable","messagePattern":"Object is not iterable","errorType":"error_code","errorClass":"InterpreterError","httpStatus":null,"severity":"error","filePath":"src/smolagents/local_python_executor.py","lineNumber":329,"sourceCode":"                    result = future.result(timeout=timeout_seconds)\n                    return result\n                except FuturesTimeoutError:\n                    raise ExecutionTimeoutError(\n                        f\"Code execution exceeded the maximum execution time of {timeout_seconds} seconds\"\n                    )\n\n        return wrapper\n\n    return decorator\n\n\ndef get_iterable(obj):\n    if isinstance(obj, list):\n        return obj\n    elif hasattr(obj, \"__iter__\"):\n        return list(obj)\n    else:\n        raise InterpreterError(\"Object is not iterable\")\n\n\ndef fix_final_answer_code(code: str) -> str:\n    \"\"\"\n    Sometimes an LLM can try to assign a variable to final_answer, which would break the final_answer() tool.\n    This function fixes this behaviour by replacing variable assignments to final_answer with final_answer_variable,\n    while preserving function calls to final_answer().\n    \"\"\"\n    # First, find if there's a direct assignment to final_answer\n    # Use word boundary and negative lookbehind to ensure it's not an object attribute\n    assignment_pattern = r\"(?<!\\.)(?<!\\w)\\bfinal_answer\\s*=\"\n    if \"final_answer(\" not in code or not re.search(assignment_pattern, code):\n        # 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.\n        # Let's not modify the code and leave the subsequent assignment error happen.\n        return code\n\n    # Pattern for replacing variable assignments\n    # Looks for 'final_answer' followed by '=' with optional whitespace","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/huggingface/smolagents/blob/30bb1161095dbae2271e6bc3cc4c219cc3897a57/src/smolagents/local_python_executor.py#L311-L347","documentation":"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.","triggerScenarios":"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]`.","commonSituations":"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.","solutions":["Inspect/guard the value before iterating: `if hasattr(x, '__iter__')` or isinstance checks, and wrap scalars ([x])","Fix the upstream expression so it produces the intended iterable (e.g. use range(n) instead of n)","Handle None returns from tools with a default: `items = tool() or []`"],"exampleFix":"# before\ncode = \"total = 0\\nfor x in len([1,2,3]):\\n    total += x\"\n\n# after\ncode = \"total = 0\\nfor x in [1,2,3]:\\n    total += x\"","handlingStrategy":"type-guard","validationCode":"def ensure_iterable(v):\n    if isinstance(v, (list, tuple)):\n        return list(v)\n    if hasattr(v, '__iter__'):\n        return list(v)\n    return [v]  # wrap scalars","typeGuard":"def is_iterable(v) -> bool:\n    return isinstance(v, (list, tuple, set, dict)) or (hasattr(v, '__iter__') and not isinstance(v, (str, bytes))) or isinstance(v, str)","tryCatchPattern":"from smolagents.local_python_executor import InterpreterError\ntry:\n    evaluate_python(code)\nexcept InterpreterError as e:\n    if 'not iterable' in str(e):\n        code = fix_loop_target(code)  # wrap the iterated value in [..]","preventionTips":["Always check a tool's return type before looping over it","Wrap scalars in a list when the model expects a collection","Default None-y results to [] with `or []`"],"tags":["smolagents","iteration","type-error","sandbox","interpreter-error"],"backgroundTag":"object-not-iterable","analyzedSha":"30bb1161095dbae2271e6bc3cc4c219cc3897a57","analyzedAt":"2026-08-28T18:52:54.169Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}