{"record":{"id":"f0035839cdbf2632","repo":"huggingface/smolagents","slug":"step-callbacks-must-be-a-list-or-a-dict","errorCode":null,"errorMessage":"step_callbacks must be a list or a dict","messagePattern":"step_callbacks must be a list or a dict","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/smolagents/agents.py","lineNumber":432,"sourceCode":"            )\n\n    def _setup_step_callbacks(self, step_callbacks):\n        # Initialize step callbacks registry\n        self.step_callbacks = CallbackRegistry()\n        if step_callbacks:\n            # Register callbacks list only for ActionStep for backward compatibility\n            if isinstance(step_callbacks, list):\n                for callback in step_callbacks:\n                    self.step_callbacks.register(ActionStep, callback)\n            # Register callbacks dict for specific step classes\n            elif isinstance(step_callbacks, dict):\n                for step_cls, callbacks in step_callbacks.items():\n                    if not isinstance(callbacks, list):\n                        callbacks = [callbacks]\n                    for callback in callbacks:\n                        self.step_callbacks.register(step_cls, callback)\n            else:\n                raise ValueError(\"step_callbacks must be a list or a dict\")\n        # Register monitor update_metrics only for ActionStep for backward compatibility\n        self.step_callbacks.register(ActionStep, self.monitor.update_metrics)\n\n    def run(\n        self,\n        task: str,\n        stream: bool = False,\n        reset: bool = True,\n        images: list[\"PIL.Image.Image\"] | None = None,\n        additional_args: dict | None = None,\n        max_steps: int | None = None,\n        return_full_result: bool | None = None,\n    ) -> Any | RunResult:\n        \"\"\"\n        Run the agent for the given task.\n\n        Args:\n            task (`str`): Task to perform.","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/huggingface/smolagents/blob/30bb1161095dbae2271e6bc3cc4c219cc3897a57/src/smolagents/agents.py#L414-L450","documentation":"The step_callbacks parameter of an agent must be either a list (applied to all step types) or a dict mapping step classes to callback(s). Anything else (a string, a bare function, a tuple, None passed explicitly with wrong type) raises ValueError('step_callbacks must be a list or a dict').","triggerScenarios":"Passing step_callbacks=some_function or step_callbacks=(cb1, cb2) or step_callbacks=\"callback\" instead of a list/dict; a single callable is not accepted and must be wrapped in a list.","commonSituations":"Intuitively passing one callback function directly; passing a tuple because other libraries accept iterables; migrating code that previously used the older single-callback signature.","solutions":["Wrap a single callback in a list: step_callbacks=[my_callback]","For per-step-type callbacks use a dict: {ActionStep: [cb1], PlanningStep: cb2}","If building callbacks dynamically, verify isinstance(cb, (list, dict)) before construction"],"exampleFix":"# before\nagent = CodeAgent(tools=[], llm_engine=llm, step_callbacks=my_callback)\n\n# after\nagent = CodeAgent(tools=[], llm_engine=llm, step_callbacks=[my_callback])","handlingStrategy":"type-guard","validationCode":"cb = my_callback if isinstance(my_callback, (list, dict)) else [my_callback]\nagent = CodeAgent(tools=[], llm_engine=llm, step_callbacks=cb)","typeGuard":"def normalize_step_callbacks(cb):\n    if isinstance(cb, dict):\n        return {k: (v if isinstance(v, list) else [v]) for k, v in cb.items()}\n    if callable(cb):\n        return [cb]\n    if isinstance(cb, list):\n        return cb\n    raise TypeError(\"step_callbacks must be a list or a dict\")","tryCatchPattern":null,"preventionTips":["Always wrap single callbacks in [ ]","Don't pass tuples; use a list literal"],"tags":["smolagents","step-callbacks","type-validation","valueerror"],"backgroundTag":"invalid-callback-registration","analyzedSha":"30bb1161095dbae2271e6bc3cc4c219cc3897a57","analyzedAt":"2026-08-28T18:52:54.169Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}