mastra-ai/mastra · error · Error

Saw text content for input CoreMessage, but the role is ${co

Error message

Saw text content for input CoreMessage, but the role is ${coreMessage.role}. This is only allowed for "system", "assistant", and "user" roles.

What it means

aiV4CoreMessageToV1PromptMessage (to-prompt.ts:29) converts an AI SDK V4 CoreMessage into a LanguageModelV1 prompt message. String content is only convertible for roles 'system', 'assistant', and 'user' — those are special-cased into a text part. If content is a string but the role is anything else (i.e. 'tool'), the converter cannot wrap it and throws.

Source

Thrown at packages/core/src/agent/message-list/conversion/to-prompt.ts:29

/**
 * Convert an AI SDK V4 CoreMessage to a V1 LanguageModel prompt message.
 * Used for creating LLM prompt messages without AI SDK streamText/generateText.
 */
export function aiV4CoreMessageToV1PromptMessage(coreMessage: CoreMessageV4): LanguageModelV1Message {
  if (coreMessage.role === `system`) {
    return coreMessage;
  }

  if (typeof coreMessage.content === `string` && (coreMessage.role === `assistant` || coreMessage.role === `user`)) {
    return {
      ...coreMessage,
      content: [{ type: 'text', text: coreMessage.content }],
    };
  }

  if (typeof coreMessage.content === `string`) {
    throw new Error(
      `Saw text content for input CoreMessage, but the role is ${coreMessage.role}. This is only allowed for "system", "assistant", and "user" roles.`,
    );
  }

  const roleContent: {
    user: Exclude<Extract<LanguageModelV1Message, { role: 'user' }>['content'], string>;
    assistant: Exclude<Extract<LanguageModelV1Message, { role: 'assistant' }>['content'], string>;
    tool: Exclude<Extract<LanguageModelV1Message, { role: 'tool' }>['content'], string>;
  } = {
    user: [],
    assistant: [],
    tool: [],
  };

  const role = coreMessage.role;

  for (const part of coreMessage.content) {
    const incompatibleMessage = `Saw incompatible message content part type ${part.type} for message role ${role}`;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Give tool-role messages array content: [{ type: 'tool-result', toolCallId, toolName, result }].
  2. If the string is a plain remark, change the role to 'user' or 'assistant' instead of 'tool'.
  3. Sanitize persisted history so tool messages always store structured tool-result parts.

Example fix

// before
{ role: 'tool', content: '42' }
// after
{ role: 'tool', content: [{ type: 'tool-result', toolCallId: 'call_1', toolName: 'getAnswer', result: '42' }] }
Defensive patterns

Strategy: validation

Validate before calling

function assertToolMessage(m: { role: string; content: unknown }) {
  if (m.role === 'tool') {
    if (typeof m.content === 'string') throw new Error('tool messages must have tool-result array content');
    if (Array.isArray(m.content) && m.content.some((p: any) => p.type !== 'tool-result'))
      throw new Error('tool messages may only contain tool-result parts');
  }
}

Type guard

function isConvertiblePromptMessage(m: { role: string; content: unknown }): boolean {
  if (typeof m.content !== 'string') return true;
  return m.role === 'system' || m.role === 'assistant' || m.role === 'user';
}

Try / catch

try {
  const prompt = messageList.toPrompt();
} catch (e) {
  if (e instanceof Error && e.message.includes('Saw text content for input CoreMessage')) {
    console.error('Tool message has string content; wrap it in a tool-result part before converting.');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the converter (directly or via MessageList.toPrompt / prompt building) with a CoreMessage of role 'tool' whose content is a plain string instead of the required array of tool-result parts.

Common situations: Hand-building tool messages; loading legacy/serialized history where tool messages were flattened to strings; a migration from another framework that models tool replies as {role:'tool',content:'result text'}.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/08995098d384541b. Report an issue: GitHub.