crewAIInc/crewAI · error · ValueError

Expected a BaseQueryEngine, got {type(query_engine)}

Error message

Expected a BaseQueryEngine, got {type(query_engine)}

What it means

LlamaIndexTool.from_query_engine type-checks its first argument against llama_index.core.query_engine.BaseQueryEngine. Passing a raw index (VectorStoreIndex), a retriever, or an object from a mismatched llama-index version fails, since the wrapper immediately feeds the object into QueryEngineTool.from_defaults which needs a real query engine.

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/llamaindex_tool/llamaindex_tool.py:65

            **kwargs,
        )

    @classmethod
    def from_query_engine(
        cls,
        query_engine: Any,
        name: str | None = None,
        description: str | None = None,
        return_direct: bool = False,
        **kwargs: Any,
    ) -> LlamaIndexTool:
        from llama_index.core.query_engine import (  # type: ignore[import-not-found]
            BaseQueryEngine,
        )
        from llama_index.core.tools import QueryEngineTool

        if not isinstance(query_engine, BaseQueryEngine):
            raise ValueError(f"Expected a BaseQueryEngine, got {type(query_engine)}")

        # NOTE: by default the schema expects an `input` variable. However this
        # confuses crewAI so we are renaming to `query`.
        class QueryToolSchema(BaseModel):
            """Schema for query tool."""

            query: str = Field(..., description="Search query for the query tool.")

        # NOTE: setting `resolve_input_errors` to True is important because the schema expects `input` but we are using `query`
        query_engine_tool = QueryEngineTool.from_defaults(
            query_engine,
            name=name,
            description=description,
            return_direct=return_direct,
            resolve_input_errors=True,
        )
        # HACK: we are replacing the schema with our custom schema
        query_engine_tool.metadata.fn_schema = QueryToolSchema

View on GitHub (pinned to 754d7323be)

Solutions

  1. Convert the index first: LlamaIndexTool.from_query_engine(index.as_query_engine(), name=..., description=...)
  2. Upgrade llama-index to a version with llama_index.core (>=0.10) to match crewai-tools' expectations
  3. Verify a single llama-index install: pip list | grep llama-index

Example fix

# before
index = VectorStoreIndex.from_documents(docs)
tool = LlamaIndexTool.from_query_engine(index)  # ValueError

# after
tool = LlamaIndexTool.from_query_engine(
    index.as_query_engine(),
    name="doc_qa",
    description="Answer questions about the docs",
)
Defensive patterns

Strategy: type-guard

Validate before calling

def is_query_engine(obj) -> bool:
    from llama_index.core.query_engine import BaseQueryEngine
    return isinstance(obj, BaseQueryEngine)

Type guard

from typing import Any, TypeGuard

def is_query_engine(obj: Any) -> TypeGuard[Any]:
    try:
        from llama_index.core.query_engine import BaseQueryEngine
    except ImportError:
        return False
    return isinstance(obj, BaseQueryEngine)

Try / catch

try:
    tool = LlamaIndexTool.from_query_engine(engine)
except ValueError as e:
    if "Expected a BaseQueryEngine" in str(e):
        tool = LlamaIndexTool.from_query_engine(engine.as_query_engine())
    else:
        raise

Prevention

When it happens

Trigger: Calling from_query_engine(VectorStoreIndex(...)) instead of index.as_query_engine(); passing a RetrieverQueryEngine from a different llama-index install; legacy llama-index <=0.9 code where the module path is llama_index.core vs llama_index.

Common situations: Following older tutorials that passed indexes directly; forgetting the .as_query_engine() step; duplicate llama-index packages breaking isinstance.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/136abf05100ac97a. Report an issue: GitHub.