{"record":{"id":"b46276481ab8b7cc","repo":"n8n-io/n8n","slug":"message-content-must-be-a-string-or-contain-text-c","errorCode":null,"errorMessage":"Message content must be a string or contain text content","messagePattern":"Message content must be a string or contain text content","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/ai-workflow-builder.ee/evaluations/langsmith/types.ts","lineNumber":83,"sourceCode":"\n\tif (typeof content === 'string') {\n\t\treturn cleanContextTags(content);\n\t}\n\n\tif (Array.isArray(content)) {\n\t\t// Extract text from complex content\n\t\tconst textContent = content\n\t\t\t.filter((item) => item?.type === 'text')\n\t\t\t.map((item) => (item as { text: string }).text)\n\t\t\t.map(cleanContextTags)\n\t\t\t.join('\\n');\n\n\t\tif (textContent) {\n\t\t\treturn textContent;\n\t\t}\n\t}\n\n\tthrow new Error('Message content must be a string or contain text content');\n}\n","sourceCodeStart":65,"sourceCodeEnd":85,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/ai-workflow-builder.ee/evaluations/langsmith/types.ts#L65-L85","documentation":"`extractMessageContent` accepts content as either a plain string or an array of typed parts (e.g. `[{type:'text', text:'...'}]`). If content is some other shape (a number, an object, an array with no `type:'text'` items), the function cannot extract text and throws. The text-extraction path also strips context tags via `cleanContextTags`.","triggerScenarios":"A message whose `content` is a non-string scalar, an object literal, or an array containing only non-text parts (e.g. only `{type:'image_url'}`). Also: a LangSmith SDK version that changed the content shape, or a custom message class whose `content` is structured differently.","commonSituations":"Multimodal examples that include only image/tool parts and no text; legacy message format where text lives under a different key; SDK upgrade that wraps content in an extra layer; malformed dataset upload.","solutions":["Ensure each message has at least one `{type:'text', text:'...'}` part (or a top-level string `content`).","If your messages legitimately have no text, skip them at the dataset/call site rather than passing them to `extractMessageContent`.","If the SDK changed the content shape, update `extractMessageContent` to read the new field (the function already tolerates `message.kwargs?.content`)."],"exampleFix":"// before\n// message.content = [{ type: 'image_url', image_url: { url: '...' } }]  (no text part)\nconst text = extractMessageContent(message);\n// after\n// message.content = [{ type: 'text', text: 'describe this' }, { type: 'image_url', image_url: { url: '...' } }]\nconst text = extractMessageContent(message);","handlingStrategy":"type-guard","validationCode":"function hasTextContent(message: BaseMessage): boolean {\n  const c = (message as { content?: unknown }).content;\n  if (typeof c === 'string') return c.length > 0;\n  if (Array.isArray(c)) return c.some((p) => p?.type === 'text' && typeof p.text === 'string');\n  return false;\n}\nif (!hasTextContent(message)) throw new Error('message has no text part to extract');\nconst text = extractMessageContent(message);","typeGuard":"function isTextualMessage(message: unknown): message is BaseMessage {\n  if (!message || typeof message !== 'object') return false;\n  const c = (message as { content?: unknown }).content;\n  if (typeof c === 'string') return true;\n  if (Array.isArray(c)) return c.some((p) => p?.type === 'text');\n  return false;\n}","tryCatchPattern":null,"preventionTips":["Filter dataset examples to those with at least one text part before running.","Pin the LangSmith SDK version so the message `content` shape does not change under you.","If you support multimodal examples, branch on content type before calling the text-only extractor."],"tags":["langsmith","types","validation","messages","parsing"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}