mastra-ai/mastra · error · Error
countCoreSystemMessageTokens can only be used with system me
Error message
countCoreSystemMessageTokens can only be used with system messages, received role: ${message.role} What it means
countCoreSystemMessageTokens is a private helper that tokenizes a message retrieved from messageList.getAllSystemMessages(). It guards that the passed message actually has role 'system'; anything else indicates an internal invariant violation (wrong list source or malformed MessageList contents) and throws a plain Error.
Source
Thrown at packages/core/src/processors/processors/token-limiter.ts:229
},
);
}
// Remove messages that don't fit within the token budget
const keepIds = new Set(messagesToKeep.map(m => m.id));
const idsToRemove = messages.filter(m => !keepIds.has(m.id)).map(m => m.id);
if (idsToRemove.length > 0) {
messageList.removeByIds(idsToRemove);
}
}
/**
* Count tokens for a system message. Accepts both untagged and tagged system messages
* read from `messageList.getAllSystemMessages()`. Only string content is supported.
*/
private async countCoreSystemMessageTokens(message: CoreMessageV4): Promise<number> {
if (message.role !== 'system') {
throw new Error(
`countCoreSystemMessageTokens can only be used with system messages, received role: ${message.role}`,
);
}
if (typeof message.content !== 'string') {
throw new Error('countCoreSystemMessageTokens: System message content must be a string');
}
const tokenString = message.role + message.content;
return this.countTokens(tokenString) + TokenLimiterProcessor.TOKENS_PER_MESSAGE;
}
/**
* Count tokens for an input message, including overhead for message structure
*/
private async countInputMessageTokens(message: MastraDBMessage): Promise<number> {
let tokenString = message.role;View on GitHub (pinned to 75dd419e61)
Solutions
- Check what you are putting into the MessageList as system messages — only role:'system' entries belong there.
- If using a custom processor, only call countCoreSystemMessageTokens with messages from getAllSystemMessages().
- Update @mastra/core to the latest patch — this may be a fixed MessageList regression.
- Log the offending message.role and message content to find the code path inserting the wrong role.
Example fix
// before countCoreSystemMessageTokens(someUserMessage); // after if (msg.role === 'system') countCoreSystemMessageTokens(msg);
Defensive patterns
Strategy: type-guard
Type guard
function isSystemMessage(m) {
return !!m && m.role === 'system';
}
// use: if (isSystemMessage(msg)) countCoreSystemMessageTokens(msg); Prevention
- Only add role:'system' messages where system messages are expected.
- Don't call private helpers with arbitrary messages.
- Keep @mastra/core updated to avoid MessageList regressions.
When it happens
Trigger: processInputStep passes a CoreMessageV4 whose role is not 'system' to countCoreSystemMessageTokens — e.g. a MessageList regression where getAllSystemMessages() returns non-system messages, or custom code inserting developer/user-role messages into the system bucket.
Common situations: Custom processors or memory code injecting messages with unexpected roles tagged as system; upgrading @mastra/core and hitting an internal invariant change; subclassing/patching the processor and calling the helper directly with arbitrary messages.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- BUG: add handling for message role ${message.role} in messag
- TokenLimiterProcessor: No messages fit within the remaining
- Aborted by processor
- MemoryThread.${methodName}() requires an agentId. Pass it vi
- Unhandled content part type: ${(exhaustiveCheck as { type: s
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2ea3ad43e592efae.
Report an issue: GitHub.