- The smolagents dict unpacking bug treated Python’s internal spread marker as code and rejected a standard dictionary merge.
- Misleading smolagents dict unpacking errors caused an agent to resend valid code, wasting three model calls and execution steps.
- The proposed patch evaluates dictionary entries pairwise, preserving Python’s merge order and duck-typed mapping behavior.
- The incident shows why observability must track repeated agent failures, not merely report the final failed run.
Table of Contents
A tiny Python feature exposed a big agent reliability problem
The smolagents dict unpacking bug is the sort of defect that looks trivial on a GitHub diff and expensive everywhere else. A model writes a perfectly ordinary Python dictionary merge, the sandbox rejects it, and the agent tries again because the error message gives it absolutely nothing useful to work with. Three retries later, the run has burned API calls, step budget and patience.
The affected component is Hugging Face’s LocalPythonExecutor, the part of smolagents that runs Python generated by an AI agent. That boundary deserves paranoia. Models are asked to produce code; a sandbox is supposed to contain and interpret it. If the sandbox refuses valid, common syntax, the agent is effectively being graded against a rulebook it cannot see.
A developer investigating the executor with a simple fuzzer found that this line failed:
config = {**{‘temperature’: 0.7, ‘max_tokens’: 512}, ‘top_p’: 0.9}
That is standard Python. It combines dictionaries in order, with later values overriding earlier ones. It is also exactly the kind of configuration assembly an LLM will generate without breaking a sweat.
Why smolagents dict unpacking failed on valid code
The root cause sits in Python’s abstract syntax tree, or AST. A normal dictionary literal contains matching lists of key nodes and value nodes. But for a spread entry using **, Python stores None where a normal key node would be. That None is not user data. It is a parser-level signpost meaning, roughly, ‘merge the mapping represented by this value.’
LocalPythonExecutor apparently walked every dictionary key and tried to evaluate it as an expression. When it reached Python’s None marker, it fell through its supported node checks and threw an InterpreterError: ‘NoneType is not supported.’ The error was technically consistent with the executor’s internal mistake and utterly misleading for the person—or model—on the receiving end.
This distinction matters. A real null-value error might prompt an agent to change a variable, add a guard, or rewrite a call. But there was no null value in the source. The agent had written valid syntax. My read is that this is worse than a clean crash: it creates the illusion that the model made a fixable coding error when the interpreter is the thing that is wrong.
The developer reported reproducing the issue on smolagents main and version 1.26.0, then opened an issue and a proposed fix. The patch changes the logic to process keys and values as pairs. If a key is None, the executor evaluates the corresponding value as a mapping and merges it; otherwise, it performs the familiar key-value assignment. That is the essential repair behind the smolagents dict unpacking fix.

The expensive part was not the exception
A conventional program hits an exception, logs it, and stops. An agent framework often does something more ambitious: it catches the failure, gives the message back to the model, and asks it to repair its own work. That feedback loop is useful only when the feedback is truthful.
In this case, Sentry recorded three events associated with one issue. The agent retried the same valid operation repeatedly, apparently because ‘NoneType is not supported’ offered no path toward a correction. Three calls may sound minor, but multiply that behavior across a fleet of long-running coding or research agents and the bill starts to look like a taxi meter stuck in traffic. The smolagents dict unpacking failure turned a routine merge into exactly that kind of costly loop.
The smolagents dict unpacking incident is a clean example of why agent observability has to be more than stack traces. Teams need to see repeated exceptions grouped by task, the code attempted on each step, and whether the model’s purported ‘fix’ is actually different from the previous attempt. Sentry can count recurrent events; agent builders should go further and flag near-identical retries automatically.
Frankly, LLMs are often blamed too quickly for loops like this. Yes, models can be stubborn, hallucinate causes and make hilariously bad repairs. But if an execution layer tells a model that a ghost None caused the failure, it has poisoned the debugging context. The model is working from a bad incident report.
Matching CPython means handling the awkward cases
The patch’s most encouraging detail is that it was not treated as a one-line bandage. The first version reportedly checked whether an expanded object was an instance of Python’s Mapping abstract base class. An OpenAI Codex review flagged a compatibility problem: CPython does not insist on that inheritance relationship. Objects with a keys method and the expected item behavior can work as mappings too.
That prompted a shift to duck typing, checking for keys rather than a specific base class. It is the right call. Sandboxes frequently become accidental alternative Python implementations, accepting a subset of the language until a user hits some odd corner. The more their semantics diverge from CPython, the more every ordinary coding habit becomes a potential landmine.
The author added nine tests covering single and repeated spreads, override order, empty expansion, non-mapping failures and a custom duck-typed mapping. The proposed behavior mirrors Python’s rules: spreads merge left to right, later keys win, and expanding something that is not mapping-like produces a meaningful error. Those cases are central to reliable smolagents dict unpacking support.
That last part is the real win. A repaired smolagents dict unpacking path doesn’t merely make one config assignment succeed; it makes the sandbox’s failure mode honest when the input truly is invalid.
Agent frameworks need error messages built for machines
Here is the uncomfortable lesson for Hugging Face and every company shipping autonomous coding tools: error handling in agent systems is now a product surface. The audience is not only a developer reading logs at 2 a.m.; it is also a probabilistic model deciding what source code to write next. Vague errors become steering instructions, and wrong errors become a map pointing directly into a ditch.
Fuzzing ordinary valid programs against interpreters is an excellent way to catch this class of issue. The developer says four previously unreported bugs surfaced in an afternoon. That should make maintainers a little uncomfortable, but it should also be a useful nudge. Agent sandboxes are young infrastructure operating beneath increasingly expensive workflows. They need compatibility suites, adversarial tests and telemetry designed around retry behavior—not just security restrictions.
The smolagents dict unpacking fix may land as a modest maintenance patch. Still, it captures an uncomfortable truth about the agent boom: the most damaging failures are often not spectacular crashes. They are polite, plausible loops that charge you three times before anyone notices.
Frequently Asked Questions
What caused the smolagents dict unpacking error?
Python represents a dictionary spread such as **settings with a None key in its abstract syntax tree. LocalPythonExecutor tried to evaluate that internal marker as though it were a normal expression, then raised an InterpreterError saying NoneType was unsupported.
Why did the AI agent repeat the same Python code?
The executor’s error message pointed to a None value that did not exist in the generated program. Because the model received no actionable explanation of the real syntax problem, it could reproduce the same valid dictionary merge and consume another agent step.
Does Python dictionary unpacking require a Mapping object?
No. CPython accepts objects that provide the behavior needed for dictionary expansion, including a keys method and item access. The patch was revised after review to avoid rejecting custom duck-typed mapping objects that do not inherit from the Mapping abstract base class.

