mastra-ai/mastra · error

Thread with id ${id} not found

Error message

Thread with id ${id} not found

What it means

InMemoryStorage.updateThread throws when no thread exists in the in-memory store with the given id. The lookup this.db.threads.get(id) returns undefined and the library fails fast rather than silently creating or no-oping an update.

Source

Thrown at packages/core/src/storage/domains/memory/inmemory.ts:87

  async saveThread({ thread }: { thread: StorageThreadType }): Promise<StorageThreadType> {
    const key = thread.id;
    this.db.threads.set(key, thread);
    return thread;
  }

  async updateThread({
    id,
    title,
    metadata,
  }: {
    id: string;
    title?: string;
    metadata?: Record<string, unknown>;
  }): Promise<StorageThreadType> {
    const thread = this.db.threads.get(id);

    if (!thread) {
      throw new Error(`Thread with id ${id} not found`);
    }

    if (thread) {
      if (title !== undefined) thread.title = title;
      thread.metadata = { ...thread.metadata, ...metadata };
      thread.updatedAt = new Date();
    }
    return thread;
  }

  async deleteThread({ threadId }: { threadId: string }): Promise<void> {
    this.db.threads.delete(threadId);

    this.db.messages.forEach((msg, key) => {
      if (msg.thread_id === threadId) {
        this.db.messages.delete(key);
      }
    });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the thread exists (getThreadById / listThreads) before updating, or create it if missing.
  2. Persist threads with a real storage adapter (LibSQL/Postgres/etc.) so ids survive restarts.
  3. Ensure the same storage instance is used for create and update within the process.
  4. Log and handle the error as 'thread not found' (404-style) rather than a retryable failure.

Example fix

// before
await storage.updateThread({ id: threadId, title: 'New' }); // throws if missing
// after
const existing = await storage.getThreadById({ threadId });
if (!existing) {
  await storage.saveThread({ thread: { id: threadId, title: 'New', createdAt: new Date(), updatedAt: new Date(), metadata: {} } });
} else {
  await storage.updateThread({ id: threadId, title: 'New' });
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function updateThreadIfExists(storage, id, patch) {
  const existing = await storage.getThreadById({ threadId: id });
  if (!existing) return null;
  return storage.updateThread({ id, ...patch });
}

Type guard

function isThread(t: unknown): t is { id: string; title?: string; metadata?: Record<string, unknown> } {
  return !!t && typeof (t as any).id === 'string';
}

Try / catch

try {
  await storage.updateThread({ id, title });
} catch (e) {
  if (e instanceof Error && e.message === `Thread with id ${id} not found`) {
    // create the thread or return 404 to the caller
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling updateThread({ id }) with an id that was never created in the current process, or after the in-memory store was restarted/cleared; updating a thread from a different storage instance than the one that created it.

Common situations: Server restarts wiping the in-memory store while clients hold stale thread ids; switching between dev (in-memory) and prod (persistent) storage; typos or case mismatches in thread ids; tests reusing ids across fresh storage instances.

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/32ea06c1fb30d0c4. Report an issue: GitHub.