mastra-ai/mastra · error

Encountered unknown role ${role} when converting V5 ModelMes

Error message

Encountered unknown role ${role} when converting V5 ModelMessage -> V5 LanguageModelV2Message, input message: ${JSON.stringify(modelMessage, null, 2)}

What it means

aiV5ModelMessageToV2PromptMessage ends with a catch-all throw when the message role is not one of 'system' | 'user' | 'assistant' | 'tool'. Any other role string cannot be mapped to a LanguageModelV2 prompt message, so the raw message is dumped in the error for debugging.

Source

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

    return {
      ...modelMessage,
      content: roleContent[role],
    };
  }
  if (role === `user`) {
    return {
      ...modelMessage,
      content: roleContent[role],
    };
  }
  if (role === `assistant`) {
    return {
      ...modelMessage,
      content: roleContent[role],
    };
  }

  throw new Error(
    `Encountered unknown role ${role} when converting V5 ModelMessage -> V5 LanguageModelV2Message, input message: ${JSON.stringify(modelMessage, null, 2)}`,
  );
}

/**
 * Convert tool-result `media` parts in a V2 (AI SDK v5 / spec `v2`) prompt
 * using a caller-provided target content-part shape.
 *
 * Mastra's `toModelOutput` and the vendored AI SDK v5 use `{ type: 'media' }`
 * as the authored multimodal tool-result content type. Newer AI SDK provider
 * specs use different content-part shapes, so callers provide the target
 * conversion for their provider spec.
 */
function convertToolResultContent(
  prompt: LanguageModelV2Prompt,
  convertMediaPart: (contentPart: Record<string, unknown>, mediaType: string) => unknown,
): LanguageModelV2Prompt {
  return prompt.map(message => {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Normalize roles to one of 'system' | 'user' | 'assistant' | 'tool' before adding to MessageList
  2. Map framework-specific roles ('human'->'user', 'ai'->'assistant') during ingestion
  3. Inspect the JSON in the error message to find the offending message and fix its role at the source
  4. Validate input messages in your ingestion layer

Example fix

// before
{ role: 'human', content: 'hi' }
// after
{ role: 'user', content: 'hi' }
Defensive patterns

Strategy: validation

Validate before calling

const ROLES = ['system','user','assistant','tool'];
if (!ROLES.includes(msg.role)) throw new Error(`Unsupported role ${msg.role}`);

Type guard

function isKnownRole(r: string): r is 'system'|'user'|'assistant'|'tool' { return ['system','user','assistant','tool'].includes(r); }

Try / catch

try { messageList.add(msg); } catch (e) { if (e instanceof Error && e.message.includes('Encountered unknown role')) { const normalized = ROLE_MAP[msg.role] ?? 'user'; messageList.add({ ...msg, role: normalized }); } else throw e; }

Prevention

When it happens

Trigger: Passing a message with a typo'd or nonstandard role (e.g. 'function', 'developer', 'Assistant', 'human') to MessageList.add() and then generating a prompt with an AI v5 model.

Common situations: Porting from other frameworks (LangChain 'human'/'ai' roles, OpenAI 'developer' role); typos in hand-built histories; deserialized DB rows with corrupted role fields.

Related errors


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