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 processInput runs, if the processor returns a MessageList, the adapter verifies it is the SAME instance that was passed in. Returning a different MessageList would orphan conversation state, so the adapter throws PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST, instructing you to mutate the provided messageList argument instead of constructing/returning a new one.

Source

Thrown at packages/core/src/workflows/evented/workflow.ts:1193

                  text: `Processor ${processor.id} requires messageList or messages for processInput phase`,
                });
              }

              // Create source checker before processing to preserve message sources
              const idsBeforeProcessing = (messages as MastraDBMessage[]).map(m => m.id);
              const check = passThrough.messageList.makeMessageSourceChecker();

              const result = await processor.processInput({
                ...baseContext,
                messages: messages as MastraDBMessage[],
                messageList: passThrough.messageList,
                systemMessages: (systemMessages ?? []) as CoreMessage[],
              });

              if (result instanceof MessageList) {
                // Validate same instance
                if (result !== passThrough.messageList) {
                  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[],
                  passThrough.messageList,
                  idsBeforeProcessing,
                  check,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Mutate the messageList passed into processInput (e.g. messageList.add/remove) and return that same instance (or return nothing non-MessageList).
  2. Remove any new MessageList(...) / clone logic from the processor body.
  3. If transformation is needed, apply it to the existing MessageList via its API instead of rebuilding one.

Example fix

// before
async processInput({ messageList }) {
  const copy = new MessageList(messageList.get.all());
  copy.add(systemMsg);
  return copy;
}

// after
async processInput({ messageList }) {
  messageList.add(systemMsg);
  return messageList;
}
Defensive patterns

Strategy: validation

Validate before calling

function checkProcessorReturn(ret: unknown, passed: MessageList) {
  if (ret instanceof MessageList && ret !== passed) {
    throw new Error('Processor returned a different MessageList; mutate the passed-in one instead');
  }
}

Type guard

const returnsSameList = (ret: unknown, passed: MessageList): boolean =>
  !(ret instanceof MessageList) || ret === passed;

Try / catch

try {
  await runProcessorStep();
} catch (e) {
  if (e instanceof MastraError && e.id === 'PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST') {
    // fix the processor to mutate the given messageList
  }
  throw e;
}

Prevention

When it happens

Trigger: A processInput implementation that creates a new MessageList (e.g. new MessageList(otherMessages) or MessageList.from(...)) and returns it, rather than mutating the messageList parameter and returning it.

Common situations: Migrating processors from older (messages-in/messages-out) APIs; copying messages into a fresh MessageList 'for safety'; factory helpers that always build new MessageList instances.

Related errors


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