{"record":{"id":"ef760b048074568f","repo":"mastra-ai/mastra","slug":"thread-does-not-belong-to-the-active-resource","errorCode":null,"errorMessage":"Thread does not belong to the active resource","messagePattern":"Thread does not belong to the active resource","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/memory/src/tools/om-tools.ts","lineNumber":1417,"sourceCode":"          threadScope: !isResourceScope ? currentThreadId || undefined : resolvedExplicitThreadId || undefined,\n        });\n      }\n\n      // Thread listing mode\n      if (mode === 'threads') {\n        const requestedCurrentThread = explicitThreadId === 'current';\n\n        // Thread scope: return current thread info only\n        if (!isResourceScope || requestedCurrentThread) {\n          if (!currentThreadId || !memory.getThreadById) {\n            return { error: 'Could not resolve current thread.' };\n          }\n          const thread = await memory.getThreadById({ threadId: currentThreadId });\n          if (!thread) {\n            return { error: 'Could not resolve current thread.' };\n          }\n          if (isResourceScope && resourceId && thread.resourceId !== resourceId) {\n            throw new Error('Thread does not belong to the active resource');\n          }\n          return {\n            threads: `- **${thread.title || '(untitled)'}** ← current\\n  id: ${thread.id}\\n  updated: ${formatTimestamp(thread.updatedAt)} | created: ${formatTimestamp(thread.createdAt)}`,\n            count: 1,\n            page: 0,\n            hasMore: false,\n          };\n        }\n        if (!resourceId) {\n          throw new Error('Resource ID is required for recall');\n        }\n        return listThreadsForResource({\n          memory,\n          resourceId,\n          currentThreadId: currentThreadId || '',\n          page: page ?? 0,\n          limit: limit ?? 20,\n          before,","sourceCodeStart":1399,"sourceCodeEnd":1435,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/tools/om-tools.ts#L1399-L1435","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nagent.stream('hi', { resourceId: 'user-a', threadId: threadOwnedByUserB });\n// after\nconst thread = await memory.createThread({ resourceId: 'user-a', title: 'chat' });\nagent.stream('hi', { resourceId: 'user-a', threadId: thread.id });","handlingStrategy":"validation","validationCode":"const thread = await memory.getThreadById({ threadId });\nif (!thread || thread.resourceId !== resourceId) {\n  throw new Error(`Thread ${threadId} is not owned by resource ${resourceId}`);\n}","typeGuard":"function threadBelongsToResource(thread: { resourceId: string } | null, resourceId: string): boolean {\n  return !!thread && thread.resourceId === resourceId;\n}","tryCatchPattern":"try {\n  return await memoryTool.execute({ context, resourceId, threadId });\n} catch (err) {\n  if (err instanceof Error && err.message === 'Thread does not belong to the active resource') {\n    // fall back to creating a fresh thread for this resource\n    const thread = await memory.createThread({ resourceId, title: 'chat' });\n    return runWithThread(thread.id);\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["memory","authorization","multi-tenancy"],"backgroundTag":"cross-tenant-resource-access","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}