n8n-io/n8n · error · Error
Tool message is missing a tool-result content block
Error message
Tool message is missing a tool-result content block
What it means
In toLcMessage's `tool` role branch, a tool message is required to carry at least one tool-result content block (found via isN8nToolResultBlock). The Langchain ToolMessage needs a tool_call_id and content from that result; a tool message with only text/other blocks has no result to attach, so the converter rejects it rather than fabricating an empty ToolMessage.
Source
Thrown at packages/@n8n/ai-utilities/src/converters/message.ts:356
.filter(isN8nToolCallBlock)
.map((c) => ({
type: 'tool_call',
id: c.toolCallId,
name: c.toolName,
args: jsonParse<Record<string, unknown>>(c.input, { fallbackValue: {} }),
}));
const nonToolContent = lcContent.filter((c) => c.type !== 'tool_call');
return new LangchainMessages.AIMessage({
content: nonToolContent,
id: message.id,
name: message.name,
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
});
}
case 'tool': {
const toolResult = message.content.find(isN8nToolResultBlock);
if (!toolResult) {
throw new Error('Tool message is missing a tool-result content block');
}
const content =
typeof toolResult.result === 'string'
? toolResult.result
: JSON.stringify(toolResult.result);
return new LangchainMessages.ToolMessage({
content,
tool_call_id: toolResult.toolCallId,
name: message.name,
status: toolResult.isError ? 'error' : 'success',
});
}
default:
return new LangchainMessages.HumanMessage({
content: lcContent,
id: message.id,
name: message.name,
});View on GitHub (pinned to 5ac6606e81)
Solutions
- Ensure every role:'tool' message includes a tool-result content block (isN8nToolResultBlock) with toolCallId and result.
- When trimming conversation history, drop whole tool messages rather than stripping their result blocks.
- If the result is genuinely missing, convert the message to role:'user' with text instead.
Example fix
// before
{ role: 'tool', content: [{ type: 'text', text: 'done' }] }
// after
{ role: 'tool', content: [{ type: 'tool_result', toolCallId: 'call_1', result: 'done' }] } Defensive patterns
Strategy: validation
Validate before calling
import { isN8nToolResultBlock } from '@n8n/ai-utilities';
function hasToolResult(content: unknown[]): boolean {
return content.some(isN8nToolResultBlock);
}
if (msg.role === 'tool' && !hasToolResult(msg.content)) {
throw new Error('tool message must include a tool-result block');
} Type guard
function isToolMessageWithResult(m: { role: string; content: unknown[] }): boolean {
return m.role !== 'tool' || m.content.some(isN8nToolResultBlock);
} Prevention
- Always attach a tool-result block (with toolCallId + result) when building role:'tool' messages.
- When trimming history, drop whole tool messages, not their result blocks.
- If the result is missing, convert the message to role:'user' instead.
When it happens
Trigger: Constructing an n8n message with role:'tool' whose content array contains no tool-result block — e.g. only a text block, or content was stripped/filtered before conversion; a tool-reply pipeline that lost the result block in transit.
Common situations: A message-merging/trimming routine removed the tool-result block but kept role:'tool'; an LLM/provider adapter emitted a tool message with text only; truncation logic dropped tool blocks by type.
Related errors
- Provided message is not a valid Langchain message: ${JSON.st
- Failed to convert to Langchain content block: ${JSON.stringi
- Unable to convert tool to N8nTool: ${JSON.stringify(tool)}
- Run ${this.runId} is not suspended. Cannot resume.
- Reflector output must be valid JSON
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/41c4811f07caa6f4.
Report an issue: GitHub.