xai-org/x-algorithm · error · TypeError

register_task_generator expects a TaskGenerator subclass, go

Error message

register_task_generator expects a TaskGenerator subclass, got {cls!r}

What it means

register_task_generator is a class decorator/registration function that only accepts classes deriving from TaskGenerator. It explicitly type-checks at runtime because decorators are easy to misapply to functions or instances. Passing anything that is not a TaskGenerator subclass raises TypeError.

Source

Thrown at grox/core/generators/registry.py:9

from grox.config.config import TaskGeneratorConfig
from grox.core.generators.task_generator import TaskGenerator

_REGISTRY: dict[str, type[TaskGenerator]] = {}


def register_task_generator(cls: type[TaskGenerator]) -> type[TaskGenerator]:
    if not (isinstance(cls, type) and issubclass(cls, TaskGenerator)):
        raise TypeError(
            f"register_task_generator expects a TaskGenerator subclass, got {cls!r}"
        )
    if not cls.TASK_GENERATOR_TYPE:
        raise ValueError(
            f"{cls.__name__} must set TASK_GENERATOR_TYPE to be registered"
        )
    key = cls.TASK_GENERATOR_TYPE
    existing = _REGISTRY.get(key)
    if existing is not None and existing is not cls:
        raise ValueError(
            f"Duplicate generator registration for {key!r}: {existing.__name__} vs {cls.__name__}"
        )
    _REGISTRY[key] = cls
    return cls


def build(cfg: TaskGeneratorConfig) -> TaskGenerator:
    cls = _REGISTRY.get(cfg.type)

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Make the decorated object a class inheriting from TaskGenerator (or PriorityTaskGenerator-compatible base).
  2. If you meant to register an instance factory, wrap it in a TaskGenerator subclass implementing _poll/from_config.
  3. Check the decorator target isn't a function or already-instantiated object.
  4. Verify imports: ensure the name under the decorator is the class itself.

Example fix

# before
@register_task_generator
def make_tasks(): ...

# after
@register_task_generator
class MyTaskGenerator(TaskGenerator):
    TASK_GENERATOR_TYPE = "my_tasks"
Defensive patterns

Strategy: type-guard

Validate before calling

from grox.core.generators.registry import register_task_generator
from grox.core.generators.task_generator import TaskGenerator

assert isinstance(MyGen, type) and issubclass(MyGen, TaskGenerator)
register_task_generator(MyGen)

Type guard

def is_task_generator_class(obj) -> bool:
    return isinstance(obj, type) and issubclass(obj, TaskGenerator)

Try / catch

try:
    register_task_generator(obj)
except TypeError as e:
    if "TaskGenerator subclass" in str(e):
        raise TypeError(f"{obj!r} must subclass TaskGenerator") from e
    raise

Prevention

When it happens

Trigger: Using @register_task_generator on a plain function, an instance, or a class that doesn't inherit TaskGenerator; calling register_task_generator(TaskGenerator.some_function) or with an imported symbol that isn't the class you expected.

Common situations: Copy-pasting the decorator onto a helper function; refactoring a generator class into a factory function without removing the decorator; import shadowing where the decorated name resolves to a method or instance.

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/0431e0168e9c8c49. Report an issue: GitHub.