run-llama/llama_index · error · ValueError

LLM must be a FunctionCallingLLM

Error message

LLM must be a FunctionCallingLLM

What it means

RetrieverTool.call builds a query string by concatenating positional args and stringified kwargs; if both are absent/empty the query string stays empty and the tool raises, because retrieving against an empty query is meaningless. Note the guard fires only when query_str == "" exactly — empty-string args still append newline characters and pass.

Source

Thrown at llama-index-core/llama_index/core/agent/workflow/function_agent.py:110

                    current_agent_name=self.name,
                    thinking_delta=last_chat_response.additional_kwargs.get(
                        "thinking_delta", None
                    ),
                )
            )

        return last_chat_response

    async def take_step(
        self,
        ctx: AgentContext,
        llm_input: List[ChatMessage],
        tools: Sequence[AsyncBaseTool],
        memory: BaseMemory,
    ) -> AgentOutput:
        """Take a single step with the function calling agent."""
        if not self.llm.metadata.is_function_calling_model:
            raise ValueError("LLM must be a FunctionCallingLLM")

        scratchpad: List[ChatMessage] = await ctx.store.get(
            self.scratchpad_key, default=[]
        )
        current_llm_input = [*llm_input, *scratchpad]

        ctx.write_event_to_stream(
            AgentInput(input=current_llm_input, current_agent_name=self.name)
        )

        if self.streaming:
            last_chat_response = await self._get_streaming_response(
                ctx, current_llm_input, tools
            )
        else:
            last_chat_response = await self._get_response(current_llm_input, tools)

        tool_calls = self.llm.get_tool_calls_from_response(  # type: ignore

View on GitHub (pinned to afd0fef371)

Solutions

  1. Always pass the query: tool.call('What is X?') or tool.call(input='What is X?').
  2. Validate before dispatch: skip or re-prompt when the tool call has no non-empty arguments.
  3. Tighten the tool's fn_schema so the query argument is required, pushing the LLM to supply it.
  4. Catch ValueError around tool dispatch and re-ask the model for corrected arguments.

Example fix

# before
out = retriever_tool.call()  # ValueError: Cannot call query engine without inputs

# after
query = "What are the key features?"
if not query.strip():
    raise ValueError("empty query from upstream")
out = retriever_tool.call(query)
Defensive patterns

Strategy: validation

Validate before calling

if not args and not kwargs:
    raise ValueError('refusing to call retriever tool with empty input')
result = tool.call(*args, **kwargs)

Type guard

def has_tool_input(args: tuple, kwargs: dict) -> bool:
    return len(args) > 0 or len(kwargs) > 0

Try / catch

try:
    out = tool.call(*args, **kwargs)
except ValueError as e:
    if 'without inputs' in str(e):
        out = tool.call(input=clarified_query)  # re-prompt for the query
    else:
        raise

Prevention

When it happens

Trigger: Calling tool.call() with no arguments; an agent dispatching the tool with an empty arguments object (LLM emitted no tool args); programmatic tool routers that forward empty payloads.

Common situations: LLM tool calls with missing arguments (schema not enforced); custom orchestration calling tools with only empty strings; testing harnesses invoking all tools with no payload; prompt templates that leave the query field blank.

Related errors


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