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

  1. Make threadId unique per resource (e.g. `${resourceId}:conversationId`) and never reuse threads across resources.
  2. Verify the resourceId sent from the client matches the thread's owner; fix the mapping in your app state.
  3. If the thread ownership changed legitimately, create a new thread for the new resource instead of reusing the old one.
  4. 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

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


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