mastra-ai/mastra · error · MastraError
PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST
PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST
Error message
Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead. What it means
After the input phase runs, the library validates that if a processor returns a MessageList, it is the exact same instance that was passed in. Returning a freshly constructed MessageList is rejected because the workflow keeps a single source of truth for messages; swapping instances would lose in-flight state (spans, persistence, ids). Throw via MastraError with id PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST.
Source
Thrown at packages/core/src/workflows/workflow.ts:1102
// Extract messageList after null check for proper type narrowing
const checkedMessageList = passThrough.messageList;
// Create source checker before processing to preserve message sources
const idsBeforeProcessing = (messages as MastraDBMessage[]).map(m => m.id);
const check = checkedMessageList.makeMessageSourceChecker();
const result = await processor.processInput({
...baseContext,
messages: messages as MastraDBMessage[],
messageList: checkedMessageList,
systemMessages: (systemMessages ?? []) as CoreMessage[],
});
if (result instanceof MessageList) {
// Validate same instance
if (result !== checkedMessageList) {
throw new MastraError({
category: ErrorCategory.USER,
domain: ErrorDomain.MASTRA_WORKFLOW,
id: 'PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST',
text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`,
});
}
return {
...passThrough,
messages: result.get.all.db(),
systemMessages: result.getSystemMessages(),
};
} else if (Array.isArray(result)) {
// Processor returned an array of messages
ProcessorRunner.applyMessagesToMessageList(
result as MastraDBMessage[],
checkedMessageList,
idsBeforeProcessing,
check,View on GitHub (pinned to 75dd419e61)
Solutions
- Mutate the passed-in messageList (e.g. messageList.add(...)) and return it (or nothing).
- If you need to modify messages, use the provided MessageList methods instead of constructing a new one.
- Return non-MessageList results if the processor output isn't a message list.
Example fix
// before
processInput({ messageList }) {
const copy = new MessageList(messageList.get.all);
copy.add(userMsg);
return copy;
}
// after
processInput({ messageList }) {
messageList.add(userMsg);
return messageList;
} Defensive patterns
Strategy: validation
Validate before calling
const out = processor.processInput(ctx);
if (out instanceof MessageList && out !== ctx.messageList) {
throw new Error('Processor must return the same messageList instance');
} Type guard
function returnsSameList(out: unknown, expected?: MessageList): boolean {
return !(out instanceof MessageList) || out === expected;
} Try / catch
try {
await step.run(input);
} catch (e) {
if (e instanceof MastraError && e.id === 'PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST') {
console.error('Processor created a new MessageList — fix it to mutate the passed instance');
} else throw e;
} Prevention
- Always mutate the passed messageList.
- Never return new MessageList(...) from processors.
- Code-review processors for MessageList construction.
- Return undefined when no message changes are needed.
When it happens
Trigger: A processInput implementation does `return new MessageList(...)` or returns a MessageList obtained from another agent/run instead of the `messageList` argument.
Common situations: Copying the messageList to mutate it safely; reusing a MessageList cached from a previous call; misunderstanding the API and thinking a new instance must be returned.
Related errors
- PROCESSOR_MISSING_MESSAGE_LIST
- PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST
- Tripwire triggered by ${processor.id}
- PROCESSOR_MISSING_MESSAGE_LIST
- Processor tripwire triggered
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/de8519198ce0b645.
Report an issue: GitHub.