mastra-ai/mastra · error · Error
Unhandled toolInvocation.state: ${String(part.toolInvocation
Error message
Unhandled toolInvocation.state: ${String(part.toolInvocation.state)} What it means
Plain Error thrown by toUIPart in the AIV6 adapter when converting a tool part whose toolInvocation.state is not one of the handled states (e.g. 'partial-call', 'call', 'result', or an unexpected value like undefined). The adapter enumerates known invocation states and hits the default branch for anything else, indicating the message contains a toolInvocation in an unrecognized or corrupted state.
Source
Thrown at packages/core/src/agent/message-list/adapters/AIV6Adapter.ts:681
'output-available',
getDisplayTransform(part.providerMetadata, 'error', part.toolInvocation.result),
),
},
{
preliminary: part.preliminary,
approval:
part.toolInvocation.approval?.approved === true
? {
id: part.toolInvocation.approval.id,
approved: true,
reason: part.toolInvocation.approval.reason,
}
: undefined,
},
) as AIV6Type.UIMessage['parts'][number];
default:
throw new Error(`Unhandled toolInvocation.state: ${String(part.toolInvocation.state)}`);
}
}
if (part.type === 'source-document') {
return withOptionalFields(
{
type: 'source-document',
sourceId: part.sourceId,
mediaType: part.mediaType,
title: part.title,
},
{
filename: part.filename,
providerMetadata: part.providerMetadata,
},
) as AIV6Type.UIMessage['parts'][number];
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure every toolInvocation in the message has a valid state: 'partial-call', 'call', or 'result'.
- Check that message-producing and message-consuming sides use the same AI SDK v6 type versions; regenerate/normalize old persisted messages.
- Inspect String(part.toolInvocation.state) in the thrown message to identify the unexpected value and fix the producer.
- If a legitimately new state variant, upgrade @mastra/core to a version that handles it.
Example fix
// before
{ type: 'tool-invocation', toolInvocation: { toolCallId: 't1', toolName: 'weather' } } // no state
// after
{ type: 'tool-invocation', toolInvocation: { toolCallId: 't1', toolName: 'weather', state: 'result', result: {...} } } Defensive patterns
Strategy: type-guard
Validate before calling
const VALID_STATES = ['partial-call', 'call', 'result'] as const;
function assertValidToolInvocation(part: any): void {
if (part?.type === 'tool-invocation' && !VALID_STATES.includes(part.toolInvocation?.state)) {
throw new Error(`Unexpected toolInvocation.state: ${String(part.toolInvocation?.state)}`);
}
} Type guard
function hasKnownInvocationState(p: any): p is { type: 'tool-invocation'; toolInvocation: { state: 'partial-call' | 'call' | 'result' } } {
return p?.type === 'tool-invocation' && ['partial-call', 'call', 'result'].includes(p.toolInvocation?.state);
} Try / catch
try {
const uiMessage = toUIMessage(v6Message);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Unhandled toolInvocation.state')) {
logger.warn('Skipping message with unknown toolInvocation state:', e.message);
return null;
}
throw e;
} Prevention
- Keep AI SDK message-producing and consuming packages on matching versions so state enums agree.
- Never construct toolInvocation objects by hand without a valid state field.
- Normalize/validate persisted messages after upgrading AI SDK versions.
- Log String(part.toolInvocation.state) from the error to identify which producer emitted the unknown state.
When it happens
Trigger: Converting an AIV6 message containing a tool-invocation part whose state is undefined/missing, misspelled (e.g. 'complete' instead of 'result'), from a newer/older AI SDK version with an added state variant, or a hand-crafted toolInvocation object without a state field.
Common situations: Mixing message versions after upgrading AI SDK (new state enum values not yet handled by the adapter); manually constructing UI messages; persisted messages whose toolInvocation was partially deserialized; streaming interrupted leaving state unset.
Related errors
- INVALID_SYSTEM_MESSAGE_FORMAT
- MASTRA_AIV5_DATA_PART_INVALID
- Found unhandled message ${JSON.stringify(message)}
- Unhandled content part type: ${(exhaustiveCheck as { type: s
- Failed to initialize task manager: ${taskManagerResult.messa
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/dedce679fb080c6d.
Report an issue: GitHub.