n8n-io/n8n · error · Error
No message provided
Error message
No message provided
What it means
`extractMessageContent` pulls text out of a LangChain `BaseMessage`; it rejects `undefined` immediately because every downstream operation (`message.content`, `.kwargs.content`) dereferences the message. Throwing early with a precise message avoids an opaque 'cannot read properties of undefined' from the LangSmith message plumbing.
Source
Thrown at packages/@n8n/ai-workflow-builder.ee/evaluations/langsmith/types.ts:59
// Helper to format violations for display
export function formatViolations(violations: Array<{ type: string; description: string }>): string {
if (violations.length === 0) {
return 'All checks passed';
}
return `Found ${violations.length} violation(s): ${violations
.map((v) => `${v.type} - ${v.description}`)
.join('; ')}`;
}
// Generate a unique run ID
export function generateRunId(): string {
return `eval-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
}
// Validate and extract message content
export function extractMessageContent(message: BaseMessage | undefined): string {
if (!message) {
throw new Error('No message provided');
}
// @ts-expect-error We need to extract content from kwargs as that's how Langsmith messages are structured
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const content = message.content ?? message.kwargs?.content;
if (typeof content === 'string') {
return cleanContextTags(content);
}
if (Array.isArray(content)) {
// Extract text from complex content
const textContent = content
.filter((item) => item?.type === 'text')
.map((item) => (item as { text: string }).text)
.map(cleanContextTags)
.join('\n');
View on GitHub (pinned to 5ac6606e81)
Solutions
- Bounds- and presence-check before calling: `if (!messages?.[0]) throw ...; extractMessageContent(messages[0])`.
- Filter sparse entries out of the array first: `messages.filter(Boolean)`.
- At the dataset source, ensure every example has at least one well-formed message.
Example fix
// before
const text = extractMessageContent(inputs.messages[0]); // inputs.messages[0] is undefined
// after
const first = inputs.messages?.find(Boolean);
if (!first) throw new Error('dataset example has no message');
const text = extractMessageContent(first); Defensive patterns
Strategy: type-guard
Validate before calling
function firstMessage(messages: unknown[] | undefined): BaseMessage | undefined {
if (!Array.isArray(messages) || messages.length === 0) return undefined;
return messages.find((m) => m != null) as BaseMessage | undefined;
}
const m = firstMessage(inputs.messages);
if (!m) throw new Error('dataset example has no message to extract');
const text = extractMessageContent(m); Type guard
function isPresentMessage(v: unknown): v is BaseMessage {
return v != null && typeof (v as { content?: unknown }).content !== 'undefined';
} Prevention
- Always bounds- and presence-check arrays of messages before indexing.
- Filter sparse arrays (`arr.filter(Boolean)`) before picking the first element.
- Add a lint rule against bare `arr[0]` dereferences in code paths that feed `extractMessageContent`.
When it happens
Trigger: Calling `extractMessageContent(undefined)` directly, or indirectly via `extractPrompt` when `inputs.messages` exists but `messages[0]` is undefined (sparse array), or via history extraction where a turn is missing.
Common situations: Dataset example whose `messages` array is `[, something]` (hole), or a code path that calls `extractMessageContent(arr[index])` without bounds-checking; refactor that swapped a single message for an array and forgot the index.
Related errors
- Message content must be a string or contain text content
- No prompt found in inputs - expected "prompt" string or "mes
- LangSmith mode requires dataset to be a dataset name string
- LangSmith mode requires `--dataset` and does not support `--
- Cannot decrease maxIterations when resuming a run. Expected
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0df3ff3d35128e4f.
Report an issue: GitHub.