langchain-ai/deepagents · error · ValueError
max_retries must be >= 0
Error message
max_retries must be >= 0
What it means
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.
Source
Thrown at libs/code/deepagents_code/model_retry.py:1070
stream_output_is_visible: Whether message-stream chunks emitted by
this model reach a user-visible consumer; it decides the
`output_may_have_started` supersession flag on retry events.
Keep `True` unless the entire nested stream is filtered before
rendering.
Raises:
TypeError: If `max_retries` or `stream_output_is_visible` has the
wrong type.
ValueError: If `max_retries` is negative.
"""
# `True >= 0` passes and `range(True + 1)` runs two attempts, so an
# unchecked bool reads as a budget of one retry.
if isinstance(max_retries, bool):
msg = f"max_retries must be an int, got {type(max_retries).__name__}"
raise TypeError(msg)
if max_retries < 0:
msg = "max_retries must be >= 0"
raise ValueError(msg)
if not isinstance(stream_output_is_visible, bool):
msg = (
"stream_output_is_visible must be a bool, got "
f"{type(stream_output_is_visible).__name__}"
)
raise TypeError(msg)
self.max_retries = max_retries
self.stream_output_is_visible = stream_output_is_visible
@staticmethod
def _emit_stream_event(request: ModelRequest, event: dict[str, object]) -> None:
writer = getattr(getattr(request, "runtime", None), "stream_writer", None)
if writer is None:
return
try:
writer(event)
except GraphBubbleUp:
# LangGraph control flow must not be mistaken for a writer fault.View on GitHub (pinned to a1af029e6e)
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
Example fix
// before wrapped = RetryModel(inner, max_retries=depth - 1) // after wrapped = RetryModel(inner, max_retries=max(0, depth - 1))
Defensive patterns
Strategy: validation
Validate before calling
if not isinstance(max_retries, int) or isinstance(max_retries, bool) or max_retries < 0:
raise ValueError("max_retries must be >= 0") Try / catch
try:
model = RetryModel(inner, max_retries=n)
except ValueError as e:
logging.error("bad retry budget: %s", e)
model = RetryModel(inner, max_retries=0) Prevention
- Clamp computed budgets with max(0, value)
- Validate user/config input ranges at load time
- Prefer defaults over arithmetic that can go negative
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- max_retries must be an int, got {type(max_retries).__name__}
- Namespace tuple must not be empty.
- Namespace component at index {i} must not be empty.
- RubricMiddleware: `max_iterations` must be positive, got {ma
- RubricMiddleware: `grader_state_schema` is required with `bu
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/5183ba8bbb4e8dbb.
Report an issue: GitHub.