{"record":{"id":"e9e09bb1c063f819","repo":"deepset-ai/haystack","slug":"maximum-run-count-self-max-runs-per-component-r","errorCode":null,"errorMessage":"Maximum run count {self._max_runs_per_component} reached for component '${component_name}'","messagePattern":"Maximum run count (.+?) reached for component '(.+?)'","errorType":"exception","errorClass":"PipelineMaxComponentRuns","httpStatus":null,"severity":"error","filePath":"haystack/core/pipeline/base.py","lineNumber":1468,"sourceCode":"        :param priority_queue: Priority queue of component names.\n        :param component_visits: Current state of component visits.\n        :returns: The next runnable component, the component name, and its priority\n            or None if no component in the queue can run.\n        :raises: PipelineMaxComponentRuns if the next runnable component has exceeded the maximum number of runs.\n        \"\"\"\n        item = priority_queue.get()\n\n        # If no component is runnable, return None\n        if item is None:\n            return None\n\n        component_name = item[1]\n        comp = self._get_component_with_graph_metadata_and_visits(component_name, component_visits[component_name])\n        # Only raise the max run count error if the component is not blocked, since if it's blocked it means it\n        # can't run anyway.\n        if item[0] < ComponentPriority.BLOCKED and comp[\"visits\"] >= self._max_runs_per_component:\n            msg = f\"Maximum run count {self._max_runs_per_component} reached for component '{component_name}'\"\n            raise PipelineMaxComponentRuns(msg)\n        return ComponentPriority(item[0]), component_name, comp\n\n    @staticmethod\n    def _add_missing_input_defaults(\n        component_inputs: dict[str, list[dict[str, Any]]], component_input_sockets: dict[str, InputSocket]\n    ) -> dict[str, Any]:\n        \"\"\"\n        Updates the inputs with the default values for the inputs that are missing\n\n        :param component_inputs: Inputs for the component.\n        :param component_input_sockets: Input sockets of the component.\n        \"\"\"\n        for name, socket in component_input_sockets.items():\n            if not socket.is_mandatory and name not in component_inputs:\n                # NOTE: Variadic inputs expect a single default value in the function signature that matches the inner\n                # type, for example Variadic[str] = \"default\". When executed inside a pipeline, we wrap this\n                # default into a list, resulting in [\"default\"],  which is the intended behavior.\n                #","sourceCodeStart":1450,"sourceCodeEnd":1486,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/core/pipeline/base.py#L1450-L1486","documentation":"PipelineBase._get_next_runnable_component raises PipelineMaxComponentRuns when a component is about to run again but has already been visited _max_runs_per_component times (default 100). This guards against infinite loops caused by cyclic pipeline graphs, e.g. looping agents or conditional branches that keep routing back to the same component.","triggerScenarios":"Running a pipeline with a cycle (e.g. a loop/back-edge from an evaluator back to a generator or agent) that never terminates; setting pipeline.max_runs_per_component to a low value while the loop legitimately needs more iterations.","commonSituations":"Agent/tool-loop pipelines where the agent keeps re-running the same component without converging; a conditional router whose condition is never satisfied so the loop runs forever; accidental self-connect of a component.","solutions":["Inspect the loop condition: ensure the branch that exits the cycle can actually be taken (fix the router/agent stopping logic).","Raise the limit if more iterations are legitimate: pipeline.max_runs_per_component = <higher number> before run().","Remove unintended cycle edges by checking pipeline.connect() calls that create back-edges in the graph."],"exampleFix":"// before\npipeline = Pipeline(max_runs_per_component=10)  # loop needs more iterations\n// after\npipeline = Pipeline(max_runs_per_component=100)  # and verify the loop's exit condition","handlingStrategy":"validation","validationCode":"# ensure the loop can exit and the limit fits the worst-case iterations\nassert pipeline_has_exit_condition(router) , \"router loop has no exit branch\"\nassert pipeline.max_runs_per_component >= expected_max_iterations","typeGuard":"def loop_terminates(router, exit_value) -> bool:\n    return any(exit_value in cond for cond in router.output_slots())","tryCatchPattern":"try:\n    result = pipeline.run(data)\nexcept PipelineMaxComponentRuns as e:\n    logger.error(\"Loop did not converge: %s\", e)","preventionTips":["Give every cyclic pipeline a reachable exit branch","Set max_runs_per_component above the expected iteration count","Test loop pipelines with a forced non-converging case in CI"],"tags":["haystack","pipeline","infinite-loop","cycle"],"backgroundTag":"max-iterations-exceeded","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}