langchain-ai/deepagents · error · ValueError

RubricMiddleware: `grader_state_schema` is required with `bu

Error message

RubricMiddleware: `grader_state_schema` is required with `build_grader_state`.

What it means

RubricMiddleware requires `grader_state_schema` whenever a custom `build_grader_state` callback is provided, because the custom builder is expected to produce state conforming to a schema the grader agent can consume. The pairing is mandatory so the grader's typed state stays consistent; building custom state without declaring its schema is rejected at construction.

Source

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

        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
        self._grader_state_schema = grader_state_schema
        self._prepare_messages_for_grader = prepare_messages_for_grader
        self._build_grader_state = build_grader_state

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Pass grader_state_schema=<TypedDict or pydantic model matching what build_grader_state returns>.
  2. If you don't need custom state, remove the build_grader_state argument.
  3. Reuse an existing schema (e.g. RubricState extended) that covers your builder's keys.
  4. Check the docs for the expected schema shape for grader input.

Example fix

// before
RubricMiddleware(model=model, build_grader_state=build_state)
// after
class MyGraderState(RubricState):
    extra_context: str
RubricMiddleware(model=model, build_grader_state=build_state, grader_state_schema=MyGraderState)
Defensive patterns

Strategy: validation

Validate before calling

if build_grader_state is not None and grader_state_schema is None:
    raise ValueError("build_grader_state requires grader_state_schema")

Type guard

def has_builder_schema(builder: Callable | None, schema: type | None) -> bool:
    return not (builder is not None and schema is None)

Try / catch

try:
    mw = RubricMiddleware(model=model, build_grader_state=b, grader_state_schema=s)
except ValueError as e:
    if "grader_state_schema" in str(e):
        mw = RubricMiddleware(model=model, grader_state_schema=RubricState)  # drop the builder
    else:
        raise

Prevention

When it happens

Trigger: RubricMiddleware(model=..., build_grader_state=my_builder) with grader_state_schema left as None.

Common situations: Adding a custom grader state builder (extra context fields for the grader) and forgetting the matching TypedDict/pydantic schema; upgrading the library where the pairing became enforced.

Related errors


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