FoundationAgents/OpenManus · error · ValueError
Tool calls required but none provided
Error message
Tool calls required but none provided
What it means
Raised in ToolCallAgent.act() when the agent produced no tool calls while tool_choices is ToolChoice.REQUIRED. In REQUIRED mode the LLM must invoke at least one tool; an empty tool_calls list means the model answered in plain text instead. This is a hard contract violation for pipelines that depend on structured tool output.
Source
Thrown at app/agent/toolcall.py:135
# For 'auto' mode, continue with content if no commands but content exists
if self.tool_choices == ToolChoice.AUTO and not self.tool_calls:
return bool(content)
return bool(self.tool_calls)
except Exception as e:
logger.error(f"🚨 Oops! The {self.name}'s thinking process hit a snag: {e}")
self.memory.add_message(
Message.assistant_message(
f"Error encountered while processing: {str(e)}"
)
)
return False
async def act(self) -> str:
"""Execute tool calls and handle their results"""
if not self.tool_calls:
if self.tool_choices == ToolChoice.REQUIRED:
raise ValueError(TOOL_CALL_REQUIRED)
# Return last message content if no tool calls
return self.messages[-1].content or "No content or commands to execute"
results = []
for command in self.tool_calls:
# Reset base64_image for each tool call
self._current_base64_image = None
result = await self.execute_tool(command)
if self.max_observe:
result = result[: self.max_observe]
logger.info(
f"🎯 Tool '{command.function.name}' completed its mission! Result: {result}"
)
View on GitHub (pinned to 52a13f2a57)
Solutions
- Re-run think() before act() so the model gets another chance (loop think/act as the framework intends) instead of calling act() directly
- Use a model that honors tool_choice="required" (gpt-4o class models)
- If plain-text answers are acceptable, set tool_choices=ToolChoice.AUTO so act() falls back to the last message content
Example fix
# before result = await agent.act() # raises if think() produced no tool calls # after await agent.think() result = await agent.act()
Defensive patterns
Strategy: validation
Validate before calling
from app.agent.toolcall import ToolChoice
def can_act(agent) -> bool:
if agent.tool_choices == ToolChoice.REQUIRED:
return bool(agent.tool_calls)
return True Try / catch
try:
out = await agent.act()
except ValueError as e:
if "Tool calls required" in str(e):
# give the model another chance to produce tool calls
await agent.think()
out = await agent.act()
else:
raise Prevention
- Always drive the think()/act() loop rather than calling act() standalone
- Prefer ToolChoice.AUTO unless structured tool output is mandatory
- Use models that reliably honor tool_choice='required' for REQUIRED-mode pipelines
When it happens
Trigger: Agent configured with tool_choices=ToolChoice.REQUIRED ("required") but the model replies with text only; weaker models ignoring the tool_choice constraint; tool schemas not registered so the model has nothing valid to call.
Common situations: Using a model that does not support tool_choice="required" (some open-weight/local models); tools list empty at request time; temperature too high causing the model to skip tools.
Related errors
- No primary agent available
- Invalid tool_choice: {tool_choice}
- Server URL is required for SSE connection
- Command is required for stdio connection
- Unsupported connection type: {self.connection_type}
AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15).
Data as JSON: /api/errors/efd18ddae1dd462c.
Report an issue: GitHub.