langchain-ai/deepagents · error · TypeError

max_retries must be an int, got {type(max_retries).__name__}

Error message

max_retries must be an int, got {type(max_retries).__name__}

What it means

The retry wrapper's constructor validates that `max_retries` is a true integer before computing the attempt budget. Because `bool` is an `int` subclass in Python, `True >= 0` would silently pass and `range(True + 1)` would run two attempts, so booleans are rejected explicitly. A `TypeError` is raised naming the actual type received.

Source

Thrown at libs/code/deepagents_code/model_retry.py:1067

            max_retries: Startup fallback for retry attempts after the initial
                call. `0` disables retries unless the request's runtime-selected
                model carries a different provider-specific budget.
            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:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Pass an explicit integer, e.g. `max_retries=1` instead of `True`
  2. Coerce config values with `int(value)` before constructing, guarding against bools
  3. If the source is a boolean flag, decide the intended count and map it explicitly (True -> 2, False -> 0)

Example fix

// before
model = RetryModel(inner, max_retries=True)
// after
model = RetryModel(inner, max_retries=1 if flag else 0)
Defensive patterns

Strategy: type-guard

Validate before calling

if isinstance(max_retries, bool) or not isinstance(max_retries, int) or max_retries < 0:
    raise ValueError(f"max_retries must be a non-negative int, got {max_retries!r}")

Type guard

def is_valid_max_retries(v: object) -> TypeGuard[int]:
    return isinstance(v, int) and not isinstance(v, bool) and v >= 0

Prevention

When it happens

Trigger: Passing `max_retries=True` or `max_retries=False` (e.g. from a loosely-typed config value or a flag misused as a count) when constructing the retry-wrapped model in `__init__`.

Common situations: YAML/JSON configs where `true`/`false` is loaded as a bool and fed straight into the model constructor; refactoring a `retry=True` flag into `max_retries`; environment variables parsed with a truthiness shortcut.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/e7aa6faa8bc073b0. Report an issue: GitHub.