{"record":{"id":"a28155be97989e13","repo":"mastra-ai/mastra","slug":"thread-with-id-threadid-is-for-resource-with-id","errorCode":null,"errorMessage":"Thread with id ${threadId} is for resource with id ${thread.resourceId} but resource ${resourceId} was queried.","messagePattern":"Thread with id (.+?) is for resource with id (.+?) but resource (.+?) was queried\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/memory/src/index.ts","lineNumber":583,"sourceCode":"    return memoryStore.listMessagesByResourceId(args);\n  }\n\n  protected async validateThreadIsOwnedByResource(threadId: string, resourceId: string, config: MemoryConfigInternal) {\n    const resourceScope =\n      (typeof config?.semanticRecall === 'object' && config?.semanticRecall?.scope !== `thread`) ||\n      config.semanticRecall === true;\n\n    const thread = await this.getThreadById({ threadId });\n\n    // For resource-scoped semantic recall, we don't need to validate that the specific thread exists\n    // because we're searching across all threads for the resource\n    if (!thread && !resourceScope) {\n      throw new Error(`No thread found with id ${threadId}`);\n    }\n\n    // If thread exists, validate it belongs to the correct resource\n    if (thread && thread.resourceId !== resourceId) {\n      throw new Error(\n        `Thread with id ${threadId} is for resource with id ${thread.resourceId} but resource ${resourceId} was queried.`,\n      );\n    }\n  }\n\n  private createMemorySpan(\n    operationType: MemoryOperationAttributes['operationType'],\n    observabilityContext?: Partial<ObservabilityContext>,\n    input?: any,\n    attributes?: Partial<MemoryOperationAttributes>,\n  ) {\n    const currentSpan = observabilityContext?.tracingContext?.currentSpan;\n    if (!currentSpan) return undefined;\n    return currentSpan.createChildSpan({\n      type: SpanType.MEMORY_OPERATION,\n      name: `memory: ${operationType}`,\n      entityType: EntityType.MEMORY,\n      entityName: 'Memory',","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/index.ts#L565-L601","documentation":"When recalling, if the thread exists but belongs to a different resource than the resourceId passed in, this error is thrown to prevent cross-tenant data leakage. The message shows both the thread's actual resourceId and the queried one.","triggerScenarios":"memory.recall({ threadId, resourceId }) where thread.resourceId !== resourceId — e.g. passing user A's resourceId with user B's thread id, or ids swapped in the call.","commonSituations":"Multi-tenant apps where thread ids are cached per session but resource ids change (user re-login, shared threads); mixing up argument order; copying a threadId between environments.","solutions":["Verify the thread belongs to the resource before recall, or derive resourceId from the fetched thread","Do not share thread ids across resources; scope thread creation/lookup per user","Check for swapped arguments (threadId vs resourceId) in the call site"],"exampleFix":"// before\nawait memory.recall({ threadId, resourceId: currentUserId });\n// after\nconst thread = await memory.getThreadById({ threadId });\nif (thread && thread.resourceId !== currentUserId) {\n  throw new Error('Thread does not belong to this user');\n}\nawait memory.recall({ threadId, resourceId: currentUserId });","handlingStrategy":"validation","validationCode":"const thread = await memory.getThreadById({ threadId });\nif (thread && thread.resourceId !== resourceId) throw new Error('Thread/resource mismatch');","typeGuard":null,"tryCatchPattern":"try {\n  await memory.recall({ threadId, resourceId });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('is for resource with id')) {\n    // handle cross-tenant access attempt / wrong id pairing\n  } else throw e;\n}","preventionTips":["Never accept threadId/resourceId pairs from untrusted input without checking ownership","Scope thread id caching per user/session","Watch for swapped argument order in recall calls"],"tags":["memory","thread","authorization","multi-tenancy"],"backgroundTag":"resource-ownership-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}