langchain-ai/deepagents · error · ValueError

RubricMiddleware: `max_iterations` must be positive, got {ma

Error message

RubricMiddleware: `max_iterations` must be positive, got {max_iterations}.

What it means

RubricMiddleware requires `max_iterations >= 1` because the rubric loop must run the grader at least once. Zero or negative values would produce a loop that never grades, so construction fails fast with ValueError.

Source

Thrown at libs/deepagents/deepagents/middleware/rubric.py:578

        system_prompt: str | None = None,
        tools: Sequence[BaseTool] | None = None,
        grader_middleware: Sequence[AgentMiddleware[Any, Any, Any]] | None = None,
        grader_context_schema: type[Any] | None = None,
        grader_state_schema: type[AgentState[Any]] | None = None,
        prepare_messages_for_grader: Callable[[list[AnyMessage]], list[AnyMessage]] | None = None,
        build_grader_state: Callable[[RubricState, int], Mapping[str, Any]] | None = None,
        max_iterations: int = 3,
        on_evaluation: Callable[[RubricEvaluation], None] | None = None,
    ) -> None:
        if not model:
            msg = "RubricMiddleware: `model` is required."
            raise ValueError(msg)
        if not isinstance(max_iterations, int) or isinstance(max_iterations, bool):
            msg = f"RubricMiddleware: `max_iterations` must be an int, got {type(max_iterations).__name__}."
            raise TypeError(msg)
        if max_iterations < 1:
            msg = f"RubricMiddleware: `max_iterations` must be positive, got {max_iterations}."
            raise ValueError(msg)
        if grader_state_schema is None and build_grader_state is not None:
            msg = "RubricMiddleware: `grader_state_schema` is required with `build_grader_state`."
            raise ValueError(msg)
        for name, callback in (
            ("prepare_messages_for_grader", prepare_messages_for_grader),
            ("build_grader_state", build_grader_state),
        ):
            if callback is not None and not callable(callback):
                msg = f"RubricMiddleware: `{name}` must be callable."
                raise TypeError(msg)

        self.max_iterations = max_iterations
        self._model = model
        self._model_label = _configured_model_label(model)
        self._system_prompt = system_prompt or GRADER_SYSTEM_PROMPT
        self._tools: list[BaseTool] = list(tools) if tools else []
        self._grader_middleware = grader_middleware or ()
        self._grader_context_schema = grader_context_schema

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Pass at least 1: max_iterations=1 for a single grading pass.
  2. If grading should be optional, don't instantiate the middleware at all instead of passing 0.
  3. Clamp the config value: max_iterations=max(1, int(raw)).
  4. Check the config source for sentinel 0/-1 defaults.

Example fix

// before
RubricMiddleware(model=model, max_iterations=0)
// after
RubricMiddleware(model=model, max_iterations=max(1, int(config.get("max_iterations", 3))))
Defensive patterns

Strategy: validation

Validate before calling

mi = int(config.get("max_iterations", 3))
if mi < 1:
    raise ValueError(f"max_iterations must be >= 1, got {mi}")

Type guard

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

Try / catch

try:
    mw = RubricMiddleware(model=model, max_iterations=mi)
except ValueError as e:
    if "must be positive" in str(e):
        mw = RubricMiddleware(model=model, max_iterations=1)
    else:
        raise

Prevention

When it happens

Trigger: RubricMiddleware(model=..., max_iterations=0) or max_iterations=-1 — an int that is < 1.

Common situations: Config defaulting to 0 ('disabled') to turn grading off; subtracting from a counter computed elsewhere; a miscomputed env-derived value.

Related errors


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