mastra-ai/mastra · error · Error

Source thread with id ${sourceThreadId} not found

Error message

Source thread with id ${sourceThreadId} not found

What it means

cloneThread looks up the source thread by id in the in-memory thread map and throws this error if no thread with that id exists. The clone cannot proceed without a source, so it fails fast with a message containing the offending id. This is a lookup/state error, not an argument-shape error.

Source

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

        metadata: {
          ...resource.metadata,
          ...metadata,
        },
        updatedAt: new Date(),
      };
    }

    this.db.resources.set(resourceId, resource);
    return resource;
  }

  async cloneThread(args: StorageCloneThreadInput): Promise<StorageCloneThreadOutput> {
    const { sourceThreadId, newThreadId: providedThreadId, resourceId, title, metadata, options } = args;

    // Get the source thread
    const sourceThread = this.db.threads.get(sourceThreadId);
    if (!sourceThread) {
      throw new Error(`Source thread with id ${sourceThreadId} not found`);
    }

    // Use provided ID or generate a new one
    const newThreadId = providedThreadId || crypto.randomUUID();

    // Check if the new thread ID already exists
    if (this.db.threads.has(newThreadId)) {
      throw new Error(`Thread with id ${newThreadId} already exists`);
    }

    // Get messages from the source thread
    let sourceMessages = Array.from(this.db.messages.values())
      .filter((msg: StorageMessageType) => msg.thread_id === sourceThreadId)
      .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());

    // Apply message filters if provided
    if (options?.messageFilter) {
      const { startDate, endDate, messageIds } = options.messageFilter;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the thread exists with getThreadById({ threadId }) before cloning.
  2. Confirm you are connected to the same storage instance that owns the thread (in-memory stores do not share state across processes).
  3. Recreate or re-persist the source thread if the store was reset; do not rely on in-memory data surviving restarts.

Example fix

// before
await storage.cloneThread({ sourceThreadId: id, newThreadId: cloneId });
// after
const source = await storage.getThreadById({ threadId: id });
if (!source) throw new Error(`Cannot clone: thread ${id} does not exist`);
await storage.cloneThread({ sourceThreadId: id, newThreadId: cloneId });
Defensive patterns

Strategy: try-catch

Validate before calling

const source = await storage.getThreadById({ threadId: sourceThreadId });
if (!source) {
  throw new Error(`Source thread ${sourceThreadId} not found; cannot clone`);
}

Try / catch

try {
  await storage.cloneThread({ sourceThreadId, newThreadId });
} catch (e) {
  if (e instanceof Error && e.message.includes('Source thread') && e.message.includes('not found')) {
    // stale id: refresh thread list or notify user
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling cloneThread({ sourceThreadId: 'missing-id', newThreadId: 'x' }) where the source id was deleted, never created in this storage instance, or belongs to a different storage/database (e.g. after restarting an in-memory store, which wipes all data).

Common situations: Stale UI references to deleted threads; copying ids between dev/prod or between two storage instances; in-memory data lost on process restart while a client still holds the old thread id; typos in hardcoded ids.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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