langchain-ai/deepagents · error · TypeError
RubricMiddleware: `{name}` must be callable.
Error message
RubricMiddleware: `{name}` must be callable. What it means
The optional hooks `prepare_messages_for_grader` and `build_grader_state` must be callable if provided. Passing a non-callable (e.g. a class instance, dict, or string) is rejected with TypeError at construction since the middleware invokes them as functions.
Source
Thrown at libs/deepagents/deepagents/middleware/rubric.py:588
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
self._on_evaluation = on_evaluation
# Built lazily so importing the middleware doesn't construct a model
# client (which can trigger env-var lookups / API key validation).
self._grader: Any = None
self._resolved_model: BaseChatModel | None = None
def before_agent(View on GitHub (pinned to a1af029e6e)
Solutions
- Pass the function itself, not its result: build_grader_state=build_state, not build_grader_state=build_state().
- Verify with callable(fn) before constructing.
- If using a method, bind it (self.method) and confirm it's a bound method.
- Check for accidental shadowing of the function name by data.
Example fix
// before RubricMiddleware(model=model, build_grader_state=make_builder()) // after RubricMiddleware(model=model, build_grader_state=make_builder()(3) if callable_needed else build_state)
Defensive patterns
Strategy: type-guard
Validate before calling
hooks = {"prepare_messages_for_grader": prep, "build_grader_state": build}
for name, fn in hooks.items():
if fn is not None and not callable(fn):
raise TypeError(f"{name} must be callable, got {type(fn).__name__}") Type guard
def is_callback(v: object) -> TypeGuard[Callable]:
return v is None or callable(v) Try / catch
try:
mw = RubricMiddleware(model=model, build_grader_state=build)
except TypeError as e:
if "must be callable" in str(e):
mw = RubricMiddleware(model=model) # drop the bad hook
else:
raise Prevention
- Pass the function object, not the result of calling it.
- Guard config-loaded hooks with callable(fn).
- Watch for names shadowed by data (e.g. a dict named build_grader_state).
- Remember None is allowed; anything non-callable and non-None is not.
When it happens
Trigger: RubricMiddleware(model=..., prepare_messages_for_grader=my_dict) or build_grader_state=SomeClass (an uninstantiated/decorated object that isn't callable) or the result of a call like build_grader_state=make_builder() where make_builder returns non-callable data.
Common situations: Assigning the wrong variable from a config; calling the factory instead of passing the factory; forgetting a decorator like @staticmethod/@functools.wraps so the attribute isn't callable; JSON-deserialized config where functions became strings.
Related errors
- RubricMiddleware: `max_iterations` must be an int, got {type
- interpreter_ptc must be False, 'safe', 'all', or a list of t
- max_retries must be an int, got {type(max_retries).__name__}
- stream_output_is_visible must be a bool, got {type(stream_ou
- context.{key} must be a string or null, got {type(value).__n
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/5fccc01631749cbe.
Report an issue: GitHub.