mastra-ai/mastra · error

Thread ${threadId} not found

Error message

Thread ${threadId} not found

What it means

In thread-scoped working memory updates, the thread must exist because the update patches thread metadata to store working memory. If getThreadById returns null, this error is thrown before patching.

Source

Thrown at packages/memory/src/index.ts:1041

      // Use mutex to prevent race conditions when multiple concurrent calls update the same resource/thread
      const mutexKey = scope === 'resource' ? `resource-${resourceId}` : `thread-${threadId}`;
      const mutex = this.updateWorkingMemoryMutexes.has(mutexKey)
        ? this.updateWorkingMemoryMutexes.get(mutexKey)!
        : new Mutex();
      this.updateWorkingMemoryMutexes.set(mutexKey, mutex);
      const release = await mutex.acquire();

      try {
        const memoryStore = await this.getMemoryStore();
        if (scope === 'resource' && resourceId) {
          await memoryStore.updateResource({
            resourceId,
            workingMemory,
          });
        } else {
          const thread = await this.getThreadById({ threadId });
          if (!thread) {
            throw new Error(`Thread ${threadId} not found`);
          }

          await memoryStore.patchThread({
            id: threadId,
            metadata: {
              ...thread.metadata,
              workingMemory,
            },
          });
        }
      } finally {
        release();
      }

      span?.end({ output: { success: true } });
    } catch (error) {
      span?.error({ error: error as Error, endSpan: true });
      throw error;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Create the thread before updating working memory (memory.createThread or let the agent's first message create it)
  2. Verify thread existence with getThreadById before calling updateWorkingMemory
  3. Fix stale/incorrect threadId in application state

Example fix

// before
await memory.updateWorkingMemory({ threadId: newThreadId, resourceId, workingMemory });
// after
let thread = await memory.getThreadById({ threadId: newThreadId });
if (!thread) {
  thread = await memory.createThread({ resourceId, title: 'New thread' });
}
await memory.updateWorkingMemory({ threadId: thread.id, resourceId, workingMemory });
Defensive patterns

Strategy: validation

Validate before calling

const thread = await memory.getThreadById({ threadId });
if (!thread) await memory.createThread({ resourceId, title: 'Auto-created' });

Try / catch

try {
  await memory.updateWorkingMemory({ threadId, resourceId, workingMemory });
} catch (e) {
  if (e instanceof Error && e.message.includes('not found')) {
    // create the thread then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: updateWorkingMemory({ threadId, resourceId, workingMemory }) with workingMemory.scope === 'thread' and a threadId that does not exist in storage.

Common situations: Calling the update-working-memory tool before the first message creates the thread; DB reset or cleanup removed the thread; stale threadId cached in client state.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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