FoundationAgents/MetaGPT · error · ValueError

`req` must be provided as a keyword argument.

Error message

`req` must be provided as a keyword argument.

What it means

The exp_pool @enable_exp_pool decorator requires the wrapped function's request to arrive as a keyword argument named exactly `req`. _validate_params checks `"req" in self.kwargs` and raises ValueError otherwise, because the pool serializes and retrieves experiences keyed on that kwarg. Passing req positionally, or naming it differently, fails validation before the function runs.

Source

Thrown at metagpt/exp_pool/decorator.py:197

        self.exp_manager.create_exp(exp)
        self._log_exp(exp)

    @staticmethod
    def choose_wrapper(func, wrapped_func):
        """Choose how to run wrapped_func based on whether the function is asynchronous."""

        async def async_wrapper(*args, **kwargs):
            return await wrapped_func(args, kwargs)

        def sync_wrapper(*args, **kwargs):
            NestAsyncio.apply_once()
            return asyncio.get_event_loop().run_until_complete(wrapped_func(args, kwargs))

        return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper

    def _validate_params(self):
        if "req" not in self.kwargs:
            raise ValueError("`req` must be provided as a keyword argument.")

    def _generate_tag(self) -> str:
        """Generates a tag for the self.func.

        "ClassName.method_name" if the first argument is a class instance, otherwise just "function_name".
        """

        if self.args and hasattr(self.args[0], "__class__"):
            cls_name = type(self.args[0]).__name__
            return f"{cls_name}.{self.func.__name__}"

        return self.func.__name__

    async def _build_context(self) -> str:
        self.context_builder.exps = self._exps

        return await self.context_builder.build(self.kwargs["req"])

View on GitHub (pinned to 11cdf466d0)

Solutions

  1. Call the decorated function with the keyword: await obj.run(req=ExperienceRequest(...)) (or whatever request object the function expects).
  2. Rename the function's parameter to req if you control the definition, so positional-style keyword calls line up.
  3. If you cannot change callers, wrap the function: define an adapter that accepts your name and forwards req=... to the decorated target.

Example fix

# before
@enable_exp_pool
class _Run:
    async def run(self, req): ...

await runner.run("some question")  # ValueError: `req` must be provided as a keyword argument.

# after
await runner.run(req="some question")
Defensive patterns

Strategy: validation

Validate before calling

# the decorator requires this exact keyword; check your call site before invoking
assert "req" in kwargs_of_call, "decorated function must be called with req=... as a keyword argument"
await obj.run(req=req_obj)

Try / catch

try:
    await runner.run(req=q)
except ValueError as e:
    if "`req` must be provided" in str(e):
        raise TypeError("call exp-pool-decorated functions with req=<request> keyword") from e
    raise

Prevention

When it happens

Trigger: Decorating a method and calling it as obj.run(query) (positional) or obj.run(request=query) instead of obj.run(req=query); the decorator applies to both sync and async functions, both wrappers enforce the contract.

Common situations: Adding the decorator to an existing method whose parameters use a different name; refactoring call sites and dropping the `req=` keyword; copying examples that predate the keyword-argument requirement.

Related errors


AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14). Data as JSON: /api/errors/7565b7d5ea2b6f7e. Report an issue: GitHub.