{"record":{"id":"5183ba8bbb4e8dbb","repo":"langchain-ai/deepagents","slug":"max-retries-must-be-0","errorCode":null,"errorMessage":"max_retries must be >= 0","messagePattern":"max_retries must be >= 0","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/model_retry.py","lineNumber":1070,"sourceCode":"            stream_output_is_visible: Whether message-stream chunks emitted by\n                this model reach a user-visible consumer; it decides the\n                `output_may_have_started` supersession flag on retry events.\n                Keep `True` unless the entire nested stream is filtered before\n                rendering.\n\n        Raises:\n            TypeError: If `max_retries` or `stream_output_is_visible` has the\n                wrong type.\n            ValueError: If `max_retries` is negative.\n        \"\"\"\n        # `True >= 0` passes and `range(True + 1)` runs two attempts, so an\n        # unchecked bool reads as a budget of one retry.\n        if isinstance(max_retries, bool):\n            msg = f\"max_retries must be an int, got {type(max_retries).__name__}\"\n            raise TypeError(msg)\n        if max_retries < 0:\n            msg = \"max_retries must be >= 0\"\n            raise ValueError(msg)\n        if not isinstance(stream_output_is_visible, bool):\n            msg = (\n                \"stream_output_is_visible must be a bool, got \"\n                f\"{type(stream_output_is_visible).__name__}\"\n            )\n            raise TypeError(msg)\n        self.max_retries = max_retries\n        self.stream_output_is_visible = stream_output_is_visible\n\n    @staticmethod\n    def _emit_stream_event(request: ModelRequest, event: dict[str, object]) -> None:\n        writer = getattr(getattr(request, \"runtime\", None), \"stream_writer\", None)\n        if writer is None:\n            return\n        try:\n            writer(event)\n        except GraphBubbleUp:\n            # LangGraph control flow must not be mistaken for a writer fault.","sourceCodeStart":1052,"sourceCodeEnd":1088,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/model_retry.py#L1052-L1088","documentation":"The constructor rejects negative `max_retries` with a `ValueError`, since a retry budget below zero is meaningless. The check runs after the bool guard, so only real integers can reach it.","triggerScenarios":"Calling the retry-model `__init__` with `max_retries=-1` or any negative integer, typically from arithmetic like `max_retries=depth - 1` where depth is 0, or a config parsed as negative.","commonSituations":"Off-by-one arithmetic when computing retries from a recursion depth; user-supplied config with a negative value; subtracting from 0 when retries are exhausted and re-wrapping.","solutions":["Clamp the value before construction: `max_retries=max(0, computed)`","Validate user/config input at load time and reject negatives early","Default to 0 (no retries) when the computed budget would be negative"],"exampleFix":"// before\nwrapped = RetryModel(inner, max_retries=depth - 1)\n// after\nwrapped = RetryModel(inner, max_retries=max(0, depth - 1))","handlingStrategy":"validation","validationCode":"if not isinstance(max_retries, int) or isinstance(max_retries, bool) or max_retries < 0:\n    raise ValueError(\"max_retries must be >= 0\")","typeGuard":null,"tryCatchPattern":"try:\n    model = RetryModel(inner, max_retries=n)\nexcept ValueError as e:\n    logging.error(\"bad retry budget: %s\", e)\n    model = RetryModel(inner, max_retries=0)","preventionTips":["Clamp computed budgets with max(0, value)","Validate user/config input ranges at load time","Prefer defaults over arithmetic that can go negative"],"tags":["python","validation","retry","value-error"],"backgroundTag":"invalid-parameter-value","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}