run-llama/llama_index · error · ValueError

Object must be of type {QueryEngineTool}

Error message

Object must be of type {QueryEngineTool}

What it means

SimpleQueryToolNodeMapping.validate_object enforces that added objects are instances of QueryEngineTool specifically (a BaseTool subclass). Passing a generic BaseTool (e.g. FunctionTool), a plain function, or any other type raises ValueError.

Source

Thrown at llama-index-core/llama_index/core/objects/tool_node_mapping.py:133

        raise NotImplementedError("Subclasses should implement this!")

    def persist(
        self, persist_dir: str = ..., obj_node_mapping_fname: str = ...
    ) -> None:
        """Persist objs."""
        raise NotImplementedError("Subclasses should implement this!")


class SimpleQueryToolNodeMapping(BaseQueryToolNodeMapping):
    """Simple query tool mapping."""

    def __init__(self, objs: Optional[Sequence[QueryEngineTool]] = None) -> None:
        objs = objs or []
        self._tools = {tool.metadata.name: tool for tool in objs}

    def validate_object(self, obj: QueryEngineTool) -> None:
        if not isinstance(obj, QueryEngineTool):
            raise ValueError(f"Object must be of type {QueryEngineTool}")

    @classmethod
    def from_objects(
        cls, objs: Sequence[QueryEngineTool], *args: Any, **kwargs: Any
    ) -> "BaseObjectNodeMapping":
        return cls(objs)

    def _add_object(self, tool: QueryEngineTool) -> None:
        if tool.metadata.name is None:
            raise ValueError("Tool name must be set")
        self._tools[tool.metadata.name] = tool

    def to_node(self, obj: QueryEngineTool) -> TextNode:
        """To node."""
        return convert_tool_to_node(obj)

    def _from_node(self, node: BaseNode) -> QueryEngineTool:
        """From node."""

View on GitHub (pinned to afd0fef371)

Solutions

  1. Use QueryEngineTool.from_defaults(query_engine=..., metadata=ToolMetadata(name=..., description=...)) for every object added to this mapping
  2. Separate mixed tool lists: SimpleToolNodeMapping for BaseTool-family tools, SimpleQueryToolNodeMapping strictly for QueryEngineTool
  3. Convert retrievers first: RetrieverTool is not a QueryEngineTool — wrap retrievers via QueryEngine(retriever) if needed

Example fix

# before
objs = [FunctionTool.from_defaults(fn=search_fn)]  # not a QueryEngineTool
mapping = SimpleQueryToolNodeMapping.from_objects(objs)  # ValueError

# after
from llama_index.core import QueryEngine
from llama_index.core.tools import QueryEngineTool, ToolMetadata
qe_tool = QueryEngineTool.from_defaults(query_engine=QueryEngine(retriever), metadata=ToolMetadata(name="search", description="search docs"))
mapping = SimpleQueryToolNodeMapping.from_objects([qe_tool])
Defensive patterns

Strategy: type-guard

Validate before calling

from llama_index.core.tools import QueryEngineTool
bad = [o for o in objs if not isinstance(o, QueryEngineTool)]
if bad:
    raise TypeError(f"non-QueryEngineTool objects: {bad!r}; use SimpleToolNodeMapping for generic tools")

Type guard

from llama_index.core.tools import QueryEngineTool
def all_are_query_engine_tools(objs: list) -> bool:
    return all(isinstance(o, QueryEngineTool) for o in objs)

Try / catch

try:
    mapping = SimpleQueryToolNodeMapping.from_objects(objs)
except ValueError as e:
    if "must be of type" in str(e):
        qe_objs = [o for o in objs if isinstance(o, QueryEngineTool)]
        mapping = SimpleQueryToolNodeMapping.from_objects(qe_objs)
    else:
        raise

Prevention

When it happens

Trigger: SimpleQueryToolNodeMapping.from_objects(objs) / ObjectIndex.from_objects(objs, SimpleQueryToolNodeMapping) where objs contains FunctionTool, RetrieverTool, or raw callables instead of QueryEngineTool instances.

Common situations: Migrating a tool list from an agent (mixed FunctionTool + QueryEngineTool) into one query-tool ObjectIndex; passing retriever tools where query-engine tools are expected; using the wrong Simple*ToolNodeMapping class for the tool type at hand.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/8b9e05c9a64ec358. Report an issue: GitHub.