mastra-ai/mastra · error

Thread does not belong to the active resource

Error message

Thread does not belong to the active resource

What it means

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.

Source

Thrown at packages/memory/src/tools/om-tools.ts:1417

          threadScope: !isResourceScope ? currentThreadId || undefined : resolvedExplicitThreadId || undefined,
        });
      }

      // Thread listing mode
      if (mode === 'threads') {
        const requestedCurrentThread = explicitThreadId === 'current';

        // Thread scope: return current thread info only
        if (!isResourceScope || requestedCurrentThread) {
          if (!currentThreadId || !memory.getThreadById) {
            return { error: 'Could not resolve current thread.' };
          }
          const thread = await memory.getThreadById({ threadId: currentThreadId });
          if (!thread) {
            return { error: 'Could not resolve current thread.' };
          }
          if (isResourceScope && resourceId && thread.resourceId !== resourceId) {
            throw new Error('Thread does not belong to the active resource');
          }
          return {
            threads: `- **${thread.title || '(untitled)'}** ← current\n  id: ${thread.id}\n  updated: ${formatTimestamp(thread.updatedAt)} | created: ${formatTimestamp(thread.createdAt)}`,
            count: 1,
            page: 0,
            hasMore: false,
          };
        }
        if (!resourceId) {
          throw new Error('Resource ID is required for recall');
        }
        return listThreadsForResource({
          memory,
          resourceId,
          currentThreadId: currentThreadId || '',
          page: page ?? 0,
          limit: limit ?? 20,
          before,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the threadId passed to the agent belongs to the same resourceId being used.
  2. Look up the correct thread via mode="threads" scoped to the right resource instead of reusing a hardcoded threadId.
  3. Fix tenant/session wiring so resourceId and threadId are derived from the same authenticated user.

Example fix

// before
agent.stream('hi', { resourceId: 'user-a', threadId: threadOwnedByUserB });
// after
const thread = await memory.createThread({ resourceId: 'user-a', title: 'chat' });
agent.stream('hi', { resourceId: 'user-a', threadId: thread.id });
Defensive patterns

Strategy: validation

Validate before calling

const thread = await memory.getThreadById({ threadId });
if (!thread || thread.resourceId !== resourceId) {
  throw new Error(`Thread ${threadId} is not owned by resource ${resourceId}`);
}

Type guard

function threadBelongsToResource(thread: { resourceId: string } | null, resourceId: string): boolean {
  return !!thread && thread.resourceId === resourceId;
}

Try / catch

try {
  return await memoryTool.execute({ context, resourceId, threadId });
} catch (err) {
  if (err instanceof Error && err.message === 'Thread does not belong to the active resource') {
    // fall back to creating a fresh thread for this resource
    const thread = await memory.createThread({ resourceId, title: 'chat' });
    return runWithThread(thread.id);
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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