{"record":{"id":"7565b7d5ea2b6f7e","repo":"FoundationAgents/MetaGPT","slug":"req-must-be-provided-as-a-keyword-argument","errorCode":null,"errorMessage":"`req` must be provided as a keyword argument.","messagePattern":"`req` must be provided as a keyword argument\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"metagpt/exp_pool/decorator.py","lineNumber":197,"sourceCode":"        self.exp_manager.create_exp(exp)\n        self._log_exp(exp)\n\n    @staticmethod\n    def choose_wrapper(func, wrapped_func):\n        \"\"\"Choose how to run wrapped_func based on whether the function is asynchronous.\"\"\"\n\n        async def async_wrapper(*args, **kwargs):\n            return await wrapped_func(args, kwargs)\n\n        def sync_wrapper(*args, **kwargs):\n            NestAsyncio.apply_once()\n            return asyncio.get_event_loop().run_until_complete(wrapped_func(args, kwargs))\n\n        return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper\n\n    def _validate_params(self):\n        if \"req\" not in self.kwargs:\n            raise ValueError(\"`req` must be provided as a keyword argument.\")\n\n    def _generate_tag(self) -> str:\n        \"\"\"Generates a tag for the self.func.\n\n        \"ClassName.method_name\" if the first argument is a class instance, otherwise just \"function_name\".\n        \"\"\"\n\n        if self.args and hasattr(self.args[0], \"__class__\"):\n            cls_name = type(self.args[0]).__name__\n            return f\"{cls_name}.{self.func.__name__}\"\n\n        return self.func.__name__\n\n    async def _build_context(self) -> str:\n        self.context_builder.exps = self._exps\n\n        return await self.context_builder.build(self.kwargs[\"req\"])\n","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/exp_pool/decorator.py#L179-L215","documentation":"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.","triggerScenarios":" 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.","commonSituations":"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.","solutions":["Call the decorated function with the keyword: await obj.run(req=ExperienceRequest(...)) (or whatever request object the function expects).","Rename the function's parameter to req if you control the definition, so positional-style keyword calls line up.","If you cannot change callers, wrap the function: define an adapter that accepts your name and forwards req=... to the decorated target."],"exampleFix":"# before\n@enable_exp_pool\nclass _Run:\n    async def run(self, req): ...\n\nawait runner.run(\"some question\")  # ValueError: `req` must be provided as a keyword argument.\n\n# after\nawait runner.run(req=\"some question\")","handlingStrategy":"validation","validationCode":"# the decorator requires this exact keyword; check your call site before invoking\nassert \"req\" in kwargs_of_call, \"decorated function must be called with req=... as a keyword argument\"\nawait obj.run(req=req_obj)","typeGuard":null,"tryCatchPattern":"try:\n    await runner.run(req=q)\nexcept ValueError as e:\n    if \"`req` must be provided\" in str(e):\n        raise TypeError(\"call exp-pool-decorated functions with req=<request> keyword\") from e\n    raise","preventionTips":["Adopt the convention `req` everywhere: decorated function parameters and call sites use the same name.","Add a unit test that calls each decorated function once — the ValueError surfaces immediately in CI, not in production.","When wrapping third-party functions with @enable_exp_pool, write a thin adapter that forwards req=..."],"tags":["python","exp-pool","decorator","api-contract","keyword-argument"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}