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

  1. Verify the resourceId you pass matches the thread's owner: fetch the thread via memory.getThreadById({ threadId }) and check thread.resourceId
  2. Look up the correct thread for the current resource instead of reusing a stale threadId (store threadId per resourceId, e.g. threadId = `${resourceId}-main`)
  3. If the thread genuinely moved, create a new thread for the resource rather than reassigning (thread-resource binding is immutable by design)
  4. 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

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


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