agentscope-ai/agentscope · error · TypeError

factory must be a callable, got {type(factory).__name__}

Error message

factory must be a callable, got {type(factory).__name__}

What it means

agentscope's set_id_factory installs a global factory used to generate IDs for entities (messages, blocks, etc.). It requires a no-argument callable; anything non-callable (a string, a class instance, None) raises this TypeError immediately as a fail-fast guard. The factory set here affects every entity ID generated afterwards.

Source

Thrown at src/agentscope/_utils/_common.py:45

    startup to substitute a different strategy.

    .. note::
        Security-sensitive tokens (gateway tokens, Redis lock tokens)
        are **not** affected and always use ``uuid.uuid4().hex``.

    Args:
        factory (`Callable[[], str]`):
            A no-arg callable returning a string ID.

    Raises:
        TypeError: If ``factory`` is not callable.

    Example:
        >>> from agentscope import set_id_factory
        >>> set_id_factory(lambda: uuid7().hex)
    """
    if not callable(factory):
        raise TypeError(
            f"factory must be a callable, got {type(factory).__name__}",
        )
    global _id_factory
    _id_factory = factory


def set_timestamp_factory(factory: Callable[[], str]) -> None:
    """Override the global timestamp factory used by all AgentScope entities.

    Args:
        factory (`Callable[[], str]`):
            A no-arg callable returning a string ID.

    Raises:
        TypeError: If ``factory`` is not callable.
    """
    if not callable(factory):
        raise TypeError(

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Pass the callable itself, not its result: set_id_factory(uuid7) or set_id_factory(lambda: uuid7().hex)
  2. Verify with callable(factory) before setting it
  3. If the value comes from config, wrap it: set_id_factory(eval-free resolver) or functools.partial for parameterized factories

Example fix

# before
set_id_factory(uuid7().hex)  # called the function -> passed a str

# after
set_id_factory(lambda: uuid7().hex)
Defensive patterns

Strategy: type-guard

Validate before calling

if not callable(factory):
    raise TypeError(f"expected a callable, got {type(factory).__name__}")
set_id_factory(factory)

Type guard

from typing import Callable, TypeGuard

def is_id_factory(v: object) -> TypeGuard[Callable[[], str]]:
    return callable(v)

Try / catch

try:
    set_id_factory(factory)
except TypeError as e:
    if "must be a callable" in str(e):
        set_id_factory(lambda: uuid7().hex)  # sensible default
    else:
        raise

Prevention

When it happens

Trigger: Calling set_id_factory with a non-callable, e.g. set_id_factory("uuid4"), set_id_factory(uuid4()), or set_id_factory(None). Tests like test_custom_factory_affects_entities rely on this contract when injecting custom factories (e.g. lambda: uuid7().hex).

Common situations: Passing the result of calling a factory instead of the factory itself (uuid7() instead of uuid7), passing a UUID string constant, or passing a class name as a string from config. Also hitting stale global state across tests because the factory is a module-level global.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/d7134a3a65cf730b. Report an issue: GitHub.