mastra-ai/mastra · 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
When updating working memory within a thread, the memory implementation verifies that the thread belongs to the given resourceId. If the stored thread's resourceId differs from the resourceId passed in the call, this error is thrown to prevent cross-tenant/cross-user memory contamination. It is a safety check, not an infrastructure failure.
Source
Thrown at packages/core/src/memory/mock.ts:281
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: _config,
});
}
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) {
const existingRaw = await memory.getWorkingMemory({
threadId,
resourceId,
memoryConfig: _config,
});
let existingData: Record<string, unknown> | null = null;
if (existingRaw) {
try {
existingData = typeof existingRaw === 'string' ? JSON.parse(existingRaw) : existingRaw;View on GitHub (pinned to 75dd419e61)
Solutions
- Verify the resourceId you pass matches the thread's owner: fetch the thread via memory.getThreadById({ threadId }) and check thread.resourceId
- Look up the correct thread for the current resource instead of reusing a stale threadId (store threadId per resourceId, e.g. threadId = `${resourceId}-main`)
- If the thread genuinely moved, create a new thread for the resource rather than reassigning (thread-resource binding is immutable by design)
- Audit where resourceId originates (auth token vs request body) to ensure consistent values across calls
Example fix
// before
await memory.updateWorkingMemory({ threadId: 'thread-123', resourceId: currentUserId, workingMemory });
// after
const thread = await memory.getThreadById({ threadId: 'thread-123' });
if (thread.resourceId !== currentUserId) {
throw new Error('Thread belongs to a different resource');
}
await memory.updateWorkingMemory({ threadId: 'thread-123', resourceId: thread.resourceId, workingMemory }); Defensive patterns
Strategy: validation
Validate before calling
async function assertThreadOwnedByResource(memory: Memory, threadId: string, resourceId: string) {
const thread = await memory.getThreadById({ threadId });
if (!thread) throw new Error(`Thread ${threadId} not found`);
if (thread.resourceId && thread.resourceId !== resourceId) {
throw new Error(`Thread ${threadId} belongs to resource ${thread.resourceId}, not ${resourceId}`);
}
return thread;
} Type guard
const threadMatchesResource = (
thread: { resourceId?: string | null },
resourceId: string,
): boolean => !thread.resourceId || thread.resourceId === resourceId; Try / catch
try {
await memory.updateWorkingMemory({ threadId, resourceId, workingMemory });
} catch (err) {
if (err instanceof Error && err.message.includes('does not match the current resourceId')) {
// cross-resource access attempt: create/use a thread owned by this resource
const thread = await memory.createThread({ resourceId, title: 'main' });
await memory.updateWorkingMemory({ threadId: thread.id, resourceId, workingMemory });
} else throw err;
} Prevention
- Key stored thread IDs by resourceId (e.g. a per-user 'main thread' mapping) and never reuse across users
- Read resourceId from a single trusted source (auth token/session), not ad-hoc request fields
- Before cross-user operations, fetch the thread and compare thread.resourceId
- In multi-tenant tests, use distinct fixtures per resource to catch mismatches early
- Treat thread-resource binding as immutable; create a new thread instead of reassigning
When it happens
Trigger: Calling memory.updateWorkingMemory({ threadId, resourceId, ... }) — or the working-memory tool path — where the thread exists, thread.resourceId is set, and thread.resourceId !== resourceId (e.g. thread 'abc' was created for user 'user-1' but the call passes 'user-2').
Common situations: Multi-tenant apps where a session/token maps to a different user than the one who created the thread; reusing cached thread IDs across users or workspaces; copying thread IDs in tests between fixtures; a bug where resourceId is read from the wrong request field.
Related errors
- MastraClient.deleteThread() requires exactly one of agentId
- Received input message with wrong threadId. Input ${message.
- Thread ID is required for thread-scoped working memory updat
- Resource ID is required for resource-scoped working memory u
- Cannot update working memory: ${scope} ID is required
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/b62093d6f7f94ec7.
Report an issue: GitHub.