mastra-ai/mastra · error

Thread ID is required for recall

Error message

Thread ID is required for recall

What it means

The recall reader requires a `threadId` to anchor the recall operation; it throws if the value is falsy. The thread identifies which conversation's messages to read, and cursor resolution plus message ordering all depend on it.

Source

Thrown at packages/memory/src/tools/om-tools.ts:795

  threadScope?: string;
  maxTokens?: number;
}): Promise<{
  text: string;
  messageId: string;
  partIndex: number;
  role: string;
  type: string;
  truncated: boolean;
  charOffset: number;
  nextCharOffset?: number;
  note?: string;
}> {
  if (!memory || typeof memory.getMemoryStore !== 'function') {
    throw new Error('Memory instance is required for recall');
  }

  if (!threadId) {
    throw new Error('Thread ID is required for recall');
  }

  const resolved = await resolveCursorMessage(memory, cursor, {
    resourceId,
    threadScope,
    enforceThreadScope: false,
  });

  if ('hint' in resolved) {
    throw new Error(resolved.hint);
  }

  const allParts = formatMessageParts(resolved, 'high');

  if (allParts.length === 0) {
    throw new Error(
      `Message ${cursor} has no visible content (it may be an internal system message). Try a neighboring message ID instead.`,
    );

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Create or obtain the thread ID first (memory.createThread / runtime.getMemoryThread) and pass it explicitly.
  2. Guard the call: if (!threadId) skip recall or initialize the thread.
  3. When wiring the agent tool, bind threadId from the runtime context server-side rather than trusting model-provided args.

Example fix

// before
await recallMessages({ memory, threadId: thread?.id ?? '', cursor });
// after
if (!thread?.id) {
  thread = await memory.createThread({ resourceId });
}
await recallMessages({ memory, threadId: thread.id, cursor });
Defensive patterns

Strategy: validation

Validate before calling

if (!threadId) {
  throw new Error('threadId is required; create or resolve the thread before recalling.');
}

Type guard

function hasThreadId(args: { threadId?: string | null }): args is { threadId: string } {
  return typeof args.threadId === 'string' && args.threadId.length > 0;
}

Try / catch

try {
  return await recallMessages({ memory, threadId, cursor });
} catch (e) {
  if (e instanceof Error && e.message.includes('Thread ID is required')) {
    const thread = await memory.createThread({ resourceId: resourceId ?? 'default' });
    return recallMessages({ memory, threadId: thread.id, cursor });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling recallMessages/recallDetail without threadId; passing an empty-string threadId from an uninitialized variable; a chat flow that starts before a thread is created and the tool runs anyway; agent runtime not propagating memory.threadId into the tool args.

Common situations: First message of a conversation where thread creation is lazy; custom integration that constructs tool args manually; older code path that treated threadId as optional.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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