{"record":{"id":"baf43f726a518e61","repo":"microsoft/autogen","slug":"agent-factory-must-take-0-or-2-arguments-baf43f","errorCode":null,"errorMessage":"Agent factory must take 0 or 2 arguments.","messagePattern":"Agent factory must take 0 or 2 arguments\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py","lineNumber":790,"sourceCode":"\n    async def _invoke_agent_factory(\n        self,\n        agent_factory: Callable[[], T | Awaitable[T]] | Callable[[AgentRuntime, AgentId], T | Awaitable[T]],\n        agent_id: AgentId,\n    ) -> T:\n        with AgentInstantiationContext.populate_context((self, agent_id)):\n            if len(inspect.signature(agent_factory).parameters) == 0:\n                factory_one = cast(Callable[[], T], agent_factory)\n                agent = factory_one()\n            elif len(inspect.signature(agent_factory).parameters) == 2:\n                warnings.warn(\n                    \"Agent factories that take two arguments are deprecated. Use AgentInstantiationContext instead. Two arg factories will be removed in a future version.\",\n                    stacklevel=2,\n                )\n                factory_two = cast(Callable[[AgentRuntime, AgentId], T], agent_factory)\n                agent = factory_two(self, agent_id)\n            else:\n                raise ValueError(\"Agent factory must take 0 or 2 arguments.\")\n\n            if inspect.isawaitable(agent):\n                agent = cast(T, await agent)\n\n        return agent\n\n    async def _get_agent(self, agent_id: AgentId) -> Agent:\n        if agent_id in self._instantiated_agents:\n            return self._instantiated_agents[agent_id]\n\n        if agent_id.type not in self._agent_factories:\n            raise ValueError(f\"Agent with name {agent_id.type} not found.\")\n\n        agent_factory = self._agent_factories[agent_id.type]\n        agent = await self._invoke_agent_factory(agent_factory, agent_id)\n        self._instantiated_agents[agent_id] = agent\n        return agent\n","sourceCodeStart":772,"sourceCodeEnd":808,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py#L772-L808","documentation":"GrpcWorkerAgentRuntime._invoke_agent_factory supports exactly two factory signatures: zero arguments (modern style, using AgentInstantiationContext) or two arguments (runtime, agent_id — deprecated). It inspects the callable's parameter count and raises ValueError('Agent factory must take 0 or 2 arguments.') for anything else. The error occurs at agent instantiation time (when a message first arrives for the type), not at registration time, because the factory is only invoked lazily by _get_agent.","triggerScenarios":"Passing a factory with 1, 3+, keyword-only-required, or *args-style signatures that inspect.signature counts differently than 0 or 2; passing a partial or bound method whose remaining parameter count is not 0 or 2; the factory works in tests that never deliver a message, then blows up on first real message routing.","commonSituations":"Refactoring a factory to take (runtime) or (agent_id) only; using functools.partial that leaves one bound parameter; lambdas with default args miscounted after wrapping; teams testing registration but not message delivery so the failure appears only in production traffic.","solutions":["Make the factory take zero arguments and read runtime/agent id from AgentInstantiationContext.current() (the non-deprecated style)","Or take exactly (runtime, agent_id) — accepting the deprecation warning — if context injection is unsuitable","Check the callable locally: len(inspect.signature(factory).parameters) must be 0 or 2 before registering","Add an integration test that sends a message to the registered type so factory invocation errors surface in CI, not production"],"exampleFix":"# before\nasync def make_agent(agent_id):  # 1 argument -> ValueError on first message\n    return MyAgent(agent_id)\nawait runtime.register_factory('t', make_agent)\n\n# after\nfrom autogen_core import AgentInstantiationContext\ndef make_agent():\n    _rt, agent_id = AgentInstantiationContext.current()\n    return MyAgent(agent_id)\nawait runtime.register_factory('t', make_agent)","handlingStrategy":"type-guard","validationCode":"import inspect\ndef valid_factory_signature(factory) -> bool:\n    return len(inspect.signature(factory).parameters) in (0, 2)","typeGuard":"import inspect\ndef is_valid_agent_factory(factory) -> bool:\n    try:\n        return len(inspect.signature(factory).parameters) in (0, 2)\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":null,"preventionTips":["Write factories with zero parameters and use AgentInstantiationContext.current()","Validate signature with inspect before registering","Integration-test with a real message so lazy factory invocation is exercised","Avoid functools.partial/bound methods that change parameter counts"],"tags":["factory","signature","lazy-instantiation"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}