{"record":{"id":"905a69d740d8041e","repo":"mastra-ai/mastra","slug":"thread-with-id-newthreadid-already-exists","errorCode":null,"errorMessage":"Thread with id ${newThreadId} already exists","messagePattern":"Thread with id (.+?) already exists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/memory/inmemory.ts","lineNumber":666,"sourceCode":"    this.db.resources.set(resourceId, resource);\n    return resource;\n  }\n\n  async cloneThread(args: StorageCloneThreadInput): Promise<StorageCloneThreadOutput> {\n    const { sourceThreadId, newThreadId: providedThreadId, resourceId, title, metadata, options } = args;\n\n    // Get the source thread\n    const sourceThread = this.db.threads.get(sourceThreadId);\n    if (!sourceThread) {\n      throw new Error(`Source thread with id ${sourceThreadId} not found`);\n    }\n\n    // Use provided ID or generate a new one\n    const newThreadId = providedThreadId || crypto.randomUUID();\n\n    // Check if the new thread ID already exists\n    if (this.db.threads.has(newThreadId)) {\n      throw new Error(`Thread with id ${newThreadId} already exists`);\n    }\n\n    // Get messages from the source thread\n    let sourceMessages = Array.from(this.db.messages.values())\n      .filter((msg: StorageMessageType) => msg.thread_id === sourceThreadId)\n      .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n\n    // Apply message filters if provided\n    if (options?.messageFilter) {\n      const { startDate, endDate, messageIds } = options.messageFilter;\n\n      if (messageIds && messageIds.length > 0) {\n        const messageIdSet = new Set(messageIds);\n        sourceMessages = sourceMessages.filter(msg => messageIdSet.has(msg.id));\n      }\n\n      if (startDate) {\n        sourceMessages = sourceMessages.filter(msg => new Date(msg.createdAt) >= startDate);","sourceCodeStart":648,"sourceCodeEnd":684,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/memory/inmemory.ts#L648-L684","documentation":"cloneThread throws this error when the target thread id (the provided newThreadId, or a generated one in the astronomically unlikely UUID collision case) already exists in the thread map. Cloning must produce a new unique thread, so an existing target id is treated as a conflict. Only applies when newThreadId is explicitly supplied or a UUID collides.","triggerScenarios":"Calling cloneThread({ sourceThreadId, newThreadId: 'existing-id' }) where existing-id already names a thread in the store; retrying a clone that already succeeded with the same explicit id; concurrent clones racing with the same newThreadId.","commonSituations":"Re-running an idempotency-broken retry after a timeout; two users/requests cloning into the same target id; seeding scripts executed twice with fixed ids; omitting newThreadId intentionally to auto-generate (the fix for most cases).","solutions":["Omit newThreadId and let cloneThread generate a fresh crypto.randomUUID().","Check existence first: if (await storage.getThreadById({ threadId: newThreadId })) pick another id.","Treat the error as an idempotent success if the prior clone is known to have completed, or catch and retry with a new id."],"exampleFix":"// before\nawait storage.cloneThread({ sourceThreadId, newThreadId: fixedId });\n// after\nconst exists = await storage.getThreadById({ threadId: fixedId });\nif (!exists) {\n  await storage.cloneThread({ sourceThreadId });\n}","handlingStrategy":"try-catch","validationCode":"const existing = await storage.getThreadById({ threadId: newThreadId });\nif (existing) {\n  throw new Error(`Thread ${newThreadId} already exists`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await storage.cloneThread({ sourceThreadId, newThreadId });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('already exists')) {\n    // treat as idempotent success or retry with a generated id\n    await storage.cloneThread({ sourceThreadId });\n    return;\n  }\n  throw e;\n}","preventionTips":["Omit newThreadId to let the library generate a collision-proof UUID.","Use deterministic suffixes (e.g. `${sourceId}-copy-${Date.now()}`) for user-visible duplicate names.","Make clone retries idempotent by checking whether the target id was already created."],"tags":["storage","conflict","duplicate-id","thread"],"backgroundTag":"duplicate-key-conflict","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}