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
- Ensure the source defines a class inheriting from smolagents.Tool (class MyTool(Tool): ...) with name, description, inputs, output_type, and forward
- For @tool-decorated function tools, re-create them with the decorator or use the appropriate loading path rather than from_code
- 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
- from_code expects class-based tools; use the decorator for function tools
- Validate/parse code strings before loading, especially user- or LLM-generated code
- Test Hub tool.py files locally with from_code before publishing
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
- Error during jinja template rendering: {type(e).__name__}: {
- Cannot specify both 'messages' and 'steps' parameters. Use '
- The 'system_prompt' property is read-only. Use 'self.prompt_
- Agent name '{name}' must be a valid Python identifier and no
- Each tool or managed_agent should have a unique name! You pa
AI-assisted analysis of huggingface/smolagents@30bb116109 (2026-08-28).
Data as JSON: /api/errors/08dd9ff4a5b8e928.
Report an issue: GitHub.