alibaba/page-agent · error · InvokeError
NO_TOOL_CALL
NO_TOOL_CALL
Error message
No tool call found in response
What it means
After a successful LLM call, OpenAIClient.invoke expects the model to respond with a tool call; if choices[0].message.tool_calls[0].function.name is missing it throws InvokeError NO_TOOL_CALL. This happens when the model answered with plain text (or an empty message) instead of invoking one of the provided tools.
Source
Thrown at packages/llms/src/OpenAIClient.ts:183
data
)
default:
throw new InvokeError(
InvokeErrorTypes.INVALID_SCHEMA,
`Unexpected finish_reason: ${choice.finish_reason}`,
undefined,
data
)
}
// Apply normalizeResponse if provided (for fixing format issues automatically)
const normalizedData = options?.normalizeResponse ? options.normalizeResponse(data) : data
const normalizedChoice = (normalizedData as any).choices?.[0]
// Get tool name from response
const toolCallName = normalizedChoice?.message?.tool_calls?.[0]?.function?.name
if (!toolCallName) {
throw new InvokeError(
InvokeErrorTypes.NO_TOOL_CALL,
'No tool call found in response',
undefined,
data
)
}
const tool = tools[toolCallName]
if (!tool) {
throw new InvokeError(
InvokeErrorTypes.UNKNOWN,
`Tool "${toolCallName}" not found in tools`,
undefined,
data
)
}
// Extract and parse tool argumentsView on GitHub (pinned to d02db1ee7c)
Solutions
- Check error.data.choices[0].message.content to see what the model actually said
- Use a model that supports tool/function calling and ensure tools are passed on the request
- Tighten the system prompt to force tool usage; lower temperature
- If the provider uses a different response shape, normalize it via the normalizeResponse option
Example fix
// before
const res = await llm.invoke(messages, tools) // model replies with text
// after
// catch and surface the model's textual answer
try {
const res = await llm.invoke(messages, tools)
} catch (e) {
if (e.code === 'NO_TOOL_CALL') {
console.warn('Model said instead:', e.data?.choices?.[0]?.message?.content)
}
throw e
} Defensive patterns
Strategy: fallback
Validate before calling
null
Type guard
function isNoToolCallError(e: unknown): e is InvokeError {
return e instanceof InvokeError && e.code === InvokeErrorTypes.NO_TOOL_CALL
} Try / catch
try {
const res = await llm.invoke(messages, tools)
} catch (e) {
if (isNoToolCallError(e)) {
const text = e.data?.choices?.[0]?.message?.content
return { fallbackAnswer: text } // degrade gracefully to the model's text answer
}
throw e
} Prevention
- Use tool-calling-capable models
- Prompt explicitly that the model must use a tool
- Verify with a smoke-test call when switching providers
When it happens
Trigger: invoke() is called with a tools map but the model returns a natural-language completion with no tool_calls; also when a custom normalizeResponse strips or renames the tool_calls field, or the provider doesn't support function calling.
Common situations: Model doesn't support function/tool calling (e.g. some open models behind an OpenAI-compatible facade); prompt leads the model to chat instead of act; temperature too high producing conversational replies; provider returns tool calls under a different field name.
Related errors
- INVALID_TOOL_ARGS
- TOOL_EXECUTION_ERROR
- [PageAgent] LLM configuration required. Please provide: base
- [PageAgent] LLMConfig.temperature is deprecated and will be
AI-assisted analysis of alibaba/page-agent@d02db1ee7c (2026-08-28).
Data as JSON: /api/errors/f5a8614762e935dc.
Report an issue: GitHub.