huggingface/smolagents · error · ValueError

No Tool subclass found in the code.

Error message

No Tool subclass found in the code.

What it means

Tool.from_code execs the provided source and scans the resulting namespace for exactly one class subclassing Tool. If none is found, it raises ValueError. This happens when the code defines a function (e.g. via @tool) instead of a class, or defines nothing Tool-like.

Source

Thrown at src/smolagents/tools.py:588

    @classmethod
    def from_code(cls, tool_code: str, **kwargs):
        module = types.ModuleType("dynamic_tool")

        exec(tool_code, module.__dict__)

        # Find the Tool subclass
        tool_class = next(
            (
                obj
                for _, obj in inspect.getmembers(module, inspect.isclass)
                if issubclass(obj, Tool) and obj is not Tool
            ),
            None,
        )

        if tool_class is None:
            raise ValueError("No Tool subclass found in the code.")

        if not isinstance(tool_class.inputs, dict):
            tool_class.inputs = ast.literal_eval(tool_class.inputs)

        # Handle output_schema if it exists and is a string representation
        if hasattr(tool_class, "output_schema") and isinstance(tool_class.output_schema, str):
            tool_class.output_schema = ast.literal_eval(tool_class.output_schema)

        return tool_class(**kwargs)

    @staticmethod
    def from_space(
        space_id: str,
        name: str,
        description: str = "",
        api_name: str | None = None,
        token: str | None = None,
    ):

View on GitHub (pinned to 30bb116109)

Solutions

  1. Ensure the source defines a class inheriting from smolagents.Tool (class MyTool(Tool): ...) with name, description, inputs, output_type, and forward
  2. For @tool-decorated function tools, re-create them with the decorator or use the appropriate loading path rather than from_code
  3. Verify the code string isn't truncated or empty before passing it

Example fix

# before
code = '''
from smolagents import tool
@tool
def greet(name: str) -> str:
    """Greets."""
    return f"hi {name}"
'''
Tool.from_code(code)
# after
code = '''
from smolagents import Tool
class GreetTool(Tool):
    name = "greet"
    description = "Greets someone."
    inputs = {"name": {"type": "string", "description": "Who"}}
    output_type = "string"
    def forward(self, name): return f"hi {name}"
'''
Tool.from_code(code)
Defensive patterns

Strategy: validation

Validate before calling

import ast
def code_defines_tool_subclass(code: str) -> bool:
    for node in ast.walk(ast.parse(code)):
        if isinstance(node, ast.ClassDef):
            for base in node.bases:
                if getattr(base, "id", "") == "Tool" or getattr(base, "attr", "") == "Tool":
                    return True
    return False

Type guard

import ast
def has_tool_subclass(code: str) -> bool:
    try:
        return code_defines_tool_subclass(code)
    except SyntaxError:
        return False

Try / catch

try:
    tool = Tool.from_code(code)
except ValueError as e:
    if "No Tool subclass" in str(e):
        raise ValueError(f"{path} does not define a Tool subclass") from e
    raise

Prevention

When it happens

Trigger: Calling Tool.from_code with source that only contains a @tool-decorated function, an plain function, or unrelated code with no Tool subclass.

Common situations: Feeding code produced by the @tool decorator into from_code (the decorator path yields a Tool instance/class differently); hand-writing a tool.py for the Hub without subclassing Tool; truncated or wrong file passed as the code string.

Related errors


AI-assisted analysis of huggingface/smolagents@30bb116109 (2026-08-28). Data as JSON: /api/errors/08dd9ff4a5b8e928. Report an issue: GitHub.