{"record":{"id":"b20ad2341b302f33","repo":"mastra-ai/mastra","slug":"source-thread-not-found","errorCode":null,"errorMessage":"Source thread not found","messagePattern":"Source thread not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"packages/server/src/server/handlers/memory.ts","lineNumber":1627,"sourceCode":"  description: 'Creates a copy of a conversation thread with all its messages',\n  tags: ['Memory'],\n  requiresAuth: true,\n  handler: async ({ mastra, agentId, threadId, newThreadId, resourceId, title, metadata, options, requestContext }) => {\n    try {\n      const effectiveThreadId = getEffectiveThreadId(requestContext, threadId);\n      const effectiveResourceId = getEffectiveResourceId(requestContext, resourceId);\n      const effectiveNewThreadId = newThreadId ?? mastra.generateId();\n      validateBody({ threadId: effectiveThreadId });\n\n      const memory = await getMemoryFromContext({ mastra, agentId, requestContext });\n      if (!memory) {\n        throw new HTTPException(400, { message: 'Memory is not initialized' });\n      }\n\n      // Validate source thread ownership\n      const sourceThread = await memory.getThreadById({ threadId: effectiveThreadId! });\n      if (!sourceThread) {\n        throw new HTTPException(404, { message: 'Source thread not found' });\n      }\n      const cloneResourceId = effectiveResourceId ?? sourceThread.resourceId ?? undefined;\n      await enforceThreadAccess({\n        mastra,\n        requestContext,\n        threadId: effectiveThreadId!,\n        thread: sourceThread,\n        effectiveResourceId,\n      });\n      await enforceThreadAccess({\n        mastra,\n        requestContext,\n        threadId: effectiveNewThreadId,\n        effectiveResourceId: cloneResourceId,\n        permission: MastraFGAPermissions.MEMORY_WRITE,\n      });\n      const result = await memory.cloneThread({\n        sourceThreadId: effectiveThreadId!,","sourceCodeStart":1609,"sourceCodeEnd":1645,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/memory.ts#L1609-L1645","documentation":"In CLONE_THREAD_ROUTE, after memory is resolved, the source thread is loaded with memory.getThreadById({ threadId }). If no thread exists for the path threadId, the handler throws HTTPException 404 'Source thread not found'. Cloning requires the source thread to be present and owned/accessible.","triggerScenarios":"POST /api/memory/threads/:threadId/clone with a threadId that does not exist in storage (already deleted, wrong environment/database, or never created), or a requestContext-threadId override pointing at a nonexistent thread.","commonSituations":"Cloning from a stale conversation list after the source thread was deleted by another user/tab; copying a threadId across dev/staging databases; racing with a delete that removes the thread before the clone executes.","solutions":["Fetch the thread first (GET /api/memory/threads/:threadId) and skip or surface the clone error if it is missing.","Confirm the threadId belongs to the same storage backend the server is configured with.","If the source list is cached, refresh it before cloning so deleted threads are not offered as clone sources.","Check any requestContext thread/resource overrides that might rewrite the effective threadId."],"exampleFix":"// before\nawait client.post(`/memory/threads/${threadId}/clone`);\n\n// after\nconst thread = await memory.getThreadById({ threadId });\nif (!thread) throw new Error(`Cannot clone: thread ${threadId} does not exist`);\nawait client.post(`/memory/threads/${threadId}/clone`);","handlingStrategy":"validation","validationCode":"const source = await memory.getThreadById({ threadId });\nif (!source) {\n  throw new Error(`Source thread ${threadId} not found; aborting clone`);\n}","typeGuard":"function isThread(t: unknown): t is { id: string; resourceId: string; title?: string } {\n  return !!t && typeof t === 'object' && typeof (t as any).id === 'string';\n}","tryCatchPattern":"try {\n  await memory.cloneThread({ sourceThreadId: threadId, newThreadId });\n} catch (e) {\n  if (e instanceof HTTPException && e.status === 404) {\n    notifyUser('This conversation no longer exists and cannot be cloned');\n    return;\n  }\n  throw e;\n}","preventionTips":["Verify the source thread exists immediately before cloning (avoid TOCTOU on cached lists).","Never copy threadIds between environments with separate databases.","Prune deleted threads from UI lists that offer clone actions."],"tags":["http-404","memory","thread","clone"],"backgroundTag":"resource-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}