microsoft/autogen · error · ValueError

Agent factory must take 0 or 2 arguments.

Error message

Agent factory must take 0 or 2 arguments.

What it means

_invoke_agent_factory introspects the factory's signature: only zero-argument factories (modern) and two-argument (runtime, agent_id) factories (deprecated) are accepted. Anything else — 1, 3+, keyword-only-required, or *args-based — raises ValueError. Note two-arg factories additionally emit a DeprecationWarning.

Source

Thrown at python/packages/autogen-core/src/autogen_core/_single_threaded_agent_runtime.py:960

    async def _invoke_agent_factory(
        self,
        agent_factory: Callable[[], T | Awaitable[T]] | Callable[[AgentRuntime, AgentId], T | Awaitable[T]],
        agent_id: AgentId,
    ) -> T:
        with AgentInstantiationContext.populate_context((self, agent_id)):
            try:
                if len(inspect.signature(agent_factory).parameters) == 0:
                    factory_one = cast(Callable[[], T], agent_factory)
                    agent = factory_one()
                elif len(inspect.signature(agent_factory).parameters) == 2:
                    warnings.warn(
                        "Agent factories that take two arguments are deprecated. Use AgentInstantiationContext instead. Two arg factories will be removed in a future version.",
                        stacklevel=2,
                    )
                    factory_two = cast(Callable[[AgentRuntime, AgentId], T], agent_factory)
                    agent = factory_two(self, agent_id)
                else:
                    raise ValueError("Agent factory must take 0 or 2 arguments.")

                if inspect.isawaitable(agent):
                    agent = cast(T, await agent)
                return agent

            except BaseException as e:
                event_logger.info(
                    AgentConstructionExceptionEvent(
                        agent_id=agent_id,
                        exception=e,
                    )
                )
                logger.error(f"Error constructing agent {agent_id}", exc_info=True)
                raise

    async def _get_agent(self, agent_id: AgentId) -> Agent:
        if agent_id in self._instantiated_agents:
            return self._instantiated_agents[agent_id]

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Close over configuration: register a lambda/partial that takes no arguments and returns the configured agent
  2. For runtime/agent_id access inside construction, use AgentInstantiationContext.current_agent_runtime()/current_agent_id() in a 0-arg factory instead of the deprecated 2-arg form
  3. Check len(inspect.signature(factory).parameters) <= 2 and that extra params have defaults before registering

Example fix

# before
await runtime.register_factory(
    AgentType("worker"), lambda cfg: WorkerAgent(cfg)  # 1-arg -> ValueError
)

# after
cfg = load_config()
await runtime.register_factory(
    AgentType("worker"), lambda: WorkerAgent(cfg)  # 0-arg closure
)
Defensive patterns

Strategy: validation

Validate before calling

import inspect

def factory_signature_valid(factory) -> bool:
    params = [p for p in inspect.signature(factory).parameters.values()
              if p.default is inspect.Parameter.empty and p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)]
    return len(params) in (0, 2)

Type guard

def is_zero_arg_factory(factory) -> bool:
    import inspect
    return len(inspect.signature(factory).parameters) == 0

Try / catch

try:
    await runtime.register_factory(t, factory)
except ValueError as e:
    if "0 or 2 arguments" in str(e):
        raise TypeError("wrap config injection in a closure/partial") from e
    raise

Prevention

When it happens

Trigger: Passing a lambda with parameters, e.g. lambda cfg: make_agent(cfg) or a bound method like self.create_agent to register_factory; factories capturing config via closure are fine, but explicit parameters other than the legacy (runtime, agent_id) pair fail; class methods whose self binding changes the parameter count unexpectedly.

Common situations: Trying to inject configuration through factory arguments instead of closures/partial; migrating code from runtimes that passed context into factories; using functools.partial incorrectly so the signature still exposes extra parameters.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/9369bda86dbea610. Report an issue: GitHub.