mastra-ai/mastra · error · MastraError
INVALID_MESSAGE_CONTENT
INVALID_MESSAGE_CONTENT
Error message
Message with role "${message.role}" must have either a 'content' property (string or array) or a 'parts' property (array) that is not empty, null, or undefined. Received message: ${JSON.stringify(message, null, 2)} What it means
MessageList.add validates that every incoming message has usable content: either a 'content' string/array or a 'parts' array. A MastraError with id INVALID_MESSAGE_CONTENT (AGENT domain, USER category) is thrown when both are missing, null, or undefined, because an empty message cannot be stored or converted to a prompt.
Source
Thrown at packages/core/src/agent/message-list/message-list.ts:1649
const existingMessage = this.getMessageById(message.id);
if (!existingMessage) return { exists: false };
return {
exists: true,
shouldReplace: !messagesAreEqual(existingMessage, message),
id: existingMessage.id,
};
}
private addOne(message: MessageInput, messageSource: MessageSource, options: MessageListAddOptions = {}) {
if (
(!(`content` in message) ||
(!message.content &&
// allow empty strings
typeof message.content !== 'string')) &&
(!(`parts` in message) || !message.parts)
) {
throw new MastraError({
id: 'INVALID_MESSAGE_CONTENT',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
text: `Message with role "${message.role}" must have either a 'content' property (string or array) or a 'parts' property (array) that is not empty, null, or undefined. Received message: ${JSON.stringify(message, null, 2)}`,
details: {
role: message.role as string,
messageSource,
hasContent: 'content' in message,
hasParts: 'parts' in message,
},
});
}
if (message.role === `system`) {
// In the past system messages were accidentally stored in the db. these should be ignored because memory is not supposed to store system messages.
if (messageSource === `memory`) return null;
// Check if the message is in a supported format for system messagesView on GitHub (pinned to 75dd419e61)
Solutions
- Ensure every message has non-null 'content' (string '' allowed) or a non-empty 'parts' array before calling add()
- Validate/sanitize client-supplied messages at your API boundary
- Fix transformation code that strips the content field
- Catch MastraError with id INVALID_MESSAGE_CONTENT and reject the input upstream with a clearer message
Example fix
// before
add({ role: 'user', content: undefined })
// after
add({ role: 'user', content: '' }) // or omit the message entirely if empty Defensive patterns
Strategy: validation
Validate before calling
function hasContent(m: any): boolean { return Boolean(m && m.role && ((('content' in m) && (typeof m.content === 'string' || Array.isArray(m.content))) || Array.isArray(m.parts))); } Type guard
function isAddableMessage(m: any): m is { role: 'user'|'assistant'|'system'|'tool'; content: string | any[] } { return !!m && ['user','assistant','system','tool'].includes(m.role) && (typeof m.content === 'string' || Array.isArray(m.content) || Array.isArray(m.parts)); } Try / catch
try { messageList.add(msg); } catch (e) { if (e instanceof MastraError && e.id === 'INVALID_MESSAGE_CONTENT') { console.warn('Skipping empty message', msg); return; } throw e; } Prevention
- Validate client-supplied message payloads before persistence
- Guard against null/undefined content in transformation pipelines
- Allow empty strings but reject null/undefined content
- Reject or drop empty messages at the API boundary
When it happens
Trigger: Adding messages like { role: 'user' } with no content, content: null, content: undefined, or an object with parts: null — via messageList.add(), Memory remember/add flows, or client-supplied message payloads.
Common situations: API clients posting empty messages; failed LLM responses persisted with undefined content; JS callers (no type checking) omitting content; mapping code that drops content during transformation.
Related errors
- INVALID_SYSTEM_MESSAGE_FORMAT
- ClaudeSDKAgent resumeData must include sessionId or continue
- CursorSDKAgent resumeData must include a message.
- CursorSDKAgent resumeData.agentId must be a string when prov
- CursorSDKAgent does not support structuredOutput because the
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/b8a7ffe060c213bd.
Report an issue: GitHub.