mastra-ai/mastra · error · Error
Thread with id ${threadId} resourceId does not match the cur
Error message
Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId} What it means
The thread found by threadId is already owned by a different resourceId than the one supplied in this request. Mastra checks thread.resourceId against the incoming resourceId to stop cross-user/cross-resource writes and memory leakage between resources.
Source
Thrown at packages/memory/src/tools/working-memory.ts:228
throw new Error('Thread ID is required for thread-scoped working memory updates');
}
if (scope === 'resource' && !resourceId) {
throw new Error('Resource ID is required for resource-scoped working memory updates');
}
if (threadId) {
let thread = await memory.getThreadById({ threadId });
if (!thread) {
thread = await memory.createThread({
threadId,
resourceId,
memoryConfig,
});
}
if (thread.resourceId && resourceId && thread.resourceId !== resourceId) {
throw new Error(`Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId}`);
}
}
let workingMemory: string;
if (usesMergeSemantics) {
// Schema-based: fetch existing, merge, save
const existingRaw = await memory.getWorkingMemory({
threadId,
resourceId,
memoryConfig,
});
let existingData: Record<string, unknown> | null = null;
if (existingRaw) {
try {
existingData = typeof existingRaw === 'string' ? JSON.parse(existingRaw) : existingRaw;
} catch {View on GitHub (pinned to 75dd419e61)
Solutions
- Make threadId unique per resource (e.g. `${resourceId}:conversationId`) and never reuse threads across resources.
- Verify the resourceId sent from the client matches the thread's owner; fix the mapping in your app state.
- If the thread ownership changed legitimately, create a new thread for the new resource instead of reusing the old one.
- In tests, generate fresh threadId/resourceId pairs per user instead of constants.
Example fix
// before
const threadId = 'shared-demo-thread'; // reused across users
// after
const threadId = `user-${resourceId}-main`; // unique per resource Defensive patterns
Strategy: validation
Validate before calling
const thread = await memory.getThreadById({ threadId });
if (thread && thread.resourceId && thread.resourceId !== resourceId) {
throw new Error(`Thread ${threadId} belongs to ${thread.resourceId}, not ${resourceId}`);
} Type guard
const threadBelongsToResource = (
thread: { resourceId?: string | null },
resourceId: string,
): boolean => !thread.resourceId || thread.resourceId === resourceId; Try / catch
try {
await agent.generate(input, { memory: { thread, resource } });
} catch (e) {
if (e instanceof Error && e.message.includes('resourceId does not match')) {
// create a new thread for this resource instead of reusing
}
} Prevention
- NamespacethreadIds by resource, e.g. `${resourceId}-${conversationId}`.
- Never accept threadId from untrusted client input; look it up server-side keyed by the authenticated resource.
- Add an assertion in tests that thread.resourceId === resourceId before reuse.
- Handle account re-keying by migrating or recreating threads.
When it happens
Trigger: Calling the agent with a memory options pair where the threadId belongs to user A but resourceId is user B (e.g. mixed-up session mapping, or reusing a hard-coded threadId across users).
Common situations: Hard-coded or cached threadIds in demos/tests reused across different resource IDs; a client passing another user's threadId; after switching auth user IDs while keeping old thread IDs; keying threads by something that changed (e.g. email -> user id).
Related errors
- AGENT_MEMORY_THREAD_RESOURCE_MISMATCH
- The workingMemory.use option has been removed. Working memor
- WORKING_MEMORY_MISSING_STORAGE_ADAPTER
- Memory instance is required for working memory updates
- Thread ID is required for thread-scoped working memory updat
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/bd53c9ccafb059ab.
Report an issue: GitHub.