vercel/ai · error · UnsupportedFunctionalityError
'system messages are only supported at the beginning of the
Error message
'system messages are only supported at the beginning of the conversation' functionality is not supported.
What it means
Google's Gemini API only accepts a system instruction as a single, leading `systemInstruction` field, not as system-role messages interleaved in the conversation. When the converter encounters a 'system' message after the conversation has started (systemMessagesAllowed is false), it throws UnsupportedFunctionalityError because there is no valid Google representation for a mid-conversation system message.
Source
Thrown at packages/google/src/convert-to-google-messages.ts:261
if (v != null) return v as Record<string, unknown>;
}
// Cross-namespace fallback (gateway interop): Vertex providers may receive
// metadata under `google`, and the Google provider may receive metadata
// under `googleVertex`/`vertex`.
if (isVertexLike) {
return part.providerOptions?.google as
| Record<string, unknown>
| undefined;
}
return (part.providerOptions?.googleVertex ??
part.providerOptions?.vertex) as Record<string, unknown> | undefined;
};
for (const { role, content } of prompt) {
switch (role) {
case 'system': {
if (!systemMessagesAllowed) {
throw new UnsupportedFunctionalityError({
functionality:
'system messages are only supported at the beginning of the conversation',
});
}
systemInstructionParts.push({ text: content });
break;
}
case 'user': {
systemMessagesAllowed = false;
const parts: GoogleContentPart[] = [];
for (const part of content) {
switch (part.type) {
case 'text': {
parts.push({ text: part.text });View on GitHub (pinned to 69428b1f8b)
Solutions
- Move all system content into a single system message at position 0 of the prompt.
- Convert mid-conversation system messages into user-role messages prefixed with instructions.
- Use the provider's `system` option (prompt-level system instruction) instead of system messages inside the array.
Example fix
// before
messages: [{ role: 'user', content: 'hi' }, { role: 'system', content: 'be brief' }]
// after
messages: [{ role: 'system', content: 'be brief' }, { role: 'user', content: 'hi' }] Defensive patterns
Strategy: validation
Validate before calling
function systemOnlyAtStart(messages) {
let seenNonSystem = false;
return messages.every(m => {
if (m.role === 'system') { if (seenNonSystem) return false; }
else seenNonSystem = true;
return true;
});
}
// validate before calling the Google model Type guard
function hasOnlyLeadingSystemMessages(prompt) {
const firstNonSystem = prompt.findIndex(m => m.role !== 'system');
return !prompt.slice(firstNonSystem + 1).some(m => m.role === 'system');
} Try / catch
try {
return await streamText({ model: googleModel, messages });
} catch (e) {
if (e?.message?.includes('system messages are only supported at the beginning')) {
const fixed = [...messages.filter(m => m.role === 'system'), ...messages.filter(m => m.role !== 'system')];
return streamText({ model: googleModel, messages: fixed });
} throw e;
} Prevention
- Keep a single system message at index 0 in prompt arrays for Google.
- In agent loops, inject per-turn instructions as user messages, not system messages.
- Add a message-shape lint/test for prompts sent to Gemini/Vertex.
When it happens
Trigger: Building a prompt array where a `{ role: 'system' }` message appears after any assistant/user message, then calling generateText/streamText with a Google (Gemini or Vertex) model. Also triggered by tool-result-then-system patterns in multi-step agent loops.
Common situations: Agent loops that inject a system reminder between turns; porting OpenAI chat histories that contain mid-conversation system messages; frameworks that append per-turn system prompts.
Related errors
- 'file parts with provider references' functionality is not s
- 'File data URLs in assistant messages are not supported' fun
- 'File data URLs in assistant messages are not supported' fun
- Multiple system messages that are separated by user/assistan
- Gemini image models do not support mask-based image editing.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/e8e2e521b2e890c9.
Report an issue: GitHub.