mastra-ai/mastra · error
Thread does not belong to the active resource
Error message
Thread does not belong to the active resource
What it means
In resource-scoped thread-listing mode, after resolving the current thread, Mastra verifies that the thread's resourceId matches the resourceId in scope. It throws when the requested thread belongs to a different resource, preventing cross-tenant/cross-user memory reads.
Source
Thrown at packages/memory/src/tools/om-tools.ts:1417
threadScope: !isResourceScope ? currentThreadId || undefined : resolvedExplicitThreadId || undefined,
});
}
// Thread listing mode
if (mode === 'threads') {
const requestedCurrentThread = explicitThreadId === 'current';
// Thread scope: return current thread info only
if (!isResourceScope || requestedCurrentThread) {
if (!currentThreadId || !memory.getThreadById) {
return { error: 'Could not resolve current thread.' };
}
const thread = await memory.getThreadById({ threadId: currentThreadId });
if (!thread) {
return { error: 'Could not resolve current thread.' };
}
if (isResourceScope && resourceId && thread.resourceId !== resourceId) {
throw new Error('Thread does not belong to the active resource');
}
return {
threads: `- **${thread.title || '(untitled)'}** ← current\n id: ${thread.id}\n updated: ${formatTimestamp(thread.updatedAt)} | created: ${formatTimestamp(thread.createdAt)}`,
count: 1,
page: 0,
hasMore: false,
};
}
if (!resourceId) {
throw new Error('Resource ID is required for recall');
}
return listThreadsForResource({
memory,
resourceId,
currentThreadId: currentThreadId || '',
page: page ?? 0,
limit: limit ?? 20,
before,View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure the threadId passed to the agent belongs to the same resourceId being used.
- Look up the correct thread via mode="threads" scoped to the right resource instead of reusing a hardcoded threadId.
- Fix tenant/session wiring so resourceId and threadId are derived from the same authenticated user.
Example fix
// before
agent.stream('hi', { resourceId: 'user-a', threadId: threadOwnedByUserB });
// after
const thread = await memory.createThread({ resourceId: 'user-a', title: 'chat' });
agent.stream('hi', { resourceId: 'user-a', threadId: thread.id }); Defensive patterns
Strategy: validation
Validate before calling
const thread = await memory.getThreadById({ threadId });
if (!thread || thread.resourceId !== resourceId) {
throw new Error(`Thread ${threadId} is not owned by resource ${resourceId}`);
} Type guard
function threadBelongsToResource(thread: { resourceId: string } | null, resourceId: string): boolean {
return !!thread && thread.resourceId === resourceId;
} Try / catch
try {
return await memoryTool.execute({ context, resourceId, threadId });
} catch (err) {
if (err instanceof Error && err.message === 'Thread does not belong to the active resource') {
// fall back to creating a fresh thread for this resource
const thread = await memory.createThread({ resourceId, title: 'chat' });
return runWithThread(thread.id);
}
throw err;
} Prevention
- Derive both resourceId and threadId from the same authenticated session/user.
- Never hardcode thread IDs; look them up per resource.
- Log resourceId+threadId pairs in dev to catch tenant mixing early.
When it happens
Trigger: mode="threads" with resource scope enabled where currentThreadId resolves to a thread whose thread.resourceId !== resourceId — typically the agent is invoked with threadId and resourceId belonging to different users.
Common situations: Passing a threadId from one user session while authenticating as another user; cached/stale thread IDs reused across accounts; copying thread IDs between test users.
Related errors
- AGENT_MEMORY_THREAD_RESOURCE_MISMATCH
- Thread with id ${threadId} is for resource with id ${thread.
- Thread not found
- Access denied: cannot save messages for a different resource
- Access denied: thread belongs to a different resource
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ef760b048074568f.
Report an issue: GitHub.