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
- Create or obtain the thread ID first (memory.createThread / runtime.getMemoryThread) and pass it explicitly.
- Guard the call: if (!threadId) skip recall or initialize the thread.
- 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
- Create the thread before the first agent turn and pass its ID into every tool call.
- Bind threadId in the tool execute closure from runtime memory context instead of model args.
- Guard chat bootstrapping so recall tools don't run pre-thread.
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
- Thread ID is required for thread-scoped working memory updat
- MastraClient.deleteThread() requires exactly one of agentId
- Resource ID is required for resource-scoped working memory u
- Thread with id ${threadId} resourceId does not match the cur
- Cannot update working memory: ${scope} ID is required
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/72eb0717aaff292a.
Report an issue: GitHub.