{"record":{"id":"7d0ef261f66fb0a9","repo":"danny-avila/LibreChat","slug":"conversation-not-found","errorCode":null,"errorMessage":"Conversation not found","messagePattern":"Conversation not found","errorType":"exception","errorClass":"Error","httpStatus":404,"severity":"error","filePath":"api/server/utils/import/fork.js","lineNumber":532,"sourceCode":"    return {\n      conversation,\n      messages,\n    };\n  });\n}\n\n/**\n * Duplicates a conversation and all its messages.\n * @param {object} params - The parameters for duplicating the conversation.\n * @param {string} params.userId - The ID of the user duplicating the conversation.\n * @param {string} params.conversationId - The ID of the conversation to duplicate.\n * @param {string} [params.title] - Optional title override for the duplicate.\n * @returns {Promise<{ conversation: TConversation, messages: TMessage[] }>} The duplicated conversation and messages.\n */\nasync function duplicateConversation({ userId, conversationId, title }) {\n  const originalConvo = await getConvo(userId, conversationId);\n  if (!originalConvo) {\n    throw new Error('Conversation not found');\n  }\n\n  const originalMessages = await getMessages({\n    user: userId,\n    conversationId,\n  });\n\n  const messagesToClone = getMessagesUpToTargetLevel(\n    originalMessages,\n    originalMessages[originalMessages.length - 1].messageId,\n  );\n\n  const importBatchBuilder = createImportBatchBuilder(userId);\n  importBatchBuilder.startConversation(originalConvo.endpoint ?? EModelEndpoint.openAI);\n\n  cloneMessagesWithTimestamps(messagesToClone, importBatchBuilder);\n\n  const duplicateTitle = title || originalConvo.title;","sourceCodeStart":514,"sourceCodeEnd":550,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/utils/import/fork.js#L514-L550","documentation":"Thrown by duplicateConversation (utils/import/fork.js) when getConvo(userId, conversationId) returns null. The conversation either does not exist, was deleted, or does not belong to the requesting user (getConvo scopes by user), so there is nothing to duplicate.","triggerScenarios":"Passing a wrong or stale conversationId; the conversation was deleted between the UI load and the duplicate click; a cross-user request where the id belongs to another user; a tenant/DB mismatch; the id is a client-generated temp id never persisted.","commonSituations":"Duplicate action on an already-deleted conversation; race between deletion and duplicate; misrouted request after a user switch; tests with fabricated ids.","solutions":["Verify the conversationId exists for the user (e.g. via a presence check or by refreshing the source list) before offering the duplicate action.","Return a 404 from the controller when getConvo yields null, instead of letting the generic error propagate.","Confirm the authenticated user matches the conversation's owner."],"exampleFix":"// before\nawait duplicateConversation({ userId, conversationId });\n\n// after\nconst existing = await getConvo(userId, conversationId);\nif (!existing) return res.status(404).json({ message: 'Conversation not found' });\nawait duplicateConversation({ userId, conversationId });","handlingStrategy":"validation","validationCode":"const originalConvo = await getConvo(userId, conversationId);\nif (!originalConvo) {\n  throw new Error('Conversation not found');\n}","typeGuard":"const conversationExistsForUser = async (userId, conversationId) => !!(await getConvo(userId, conversationId));","tryCatchPattern":"try {\n  await duplicateConversation({ userId, conversationId });\n} catch (err) {\n  if (err.message === 'Conversation not found') return res.status(404).json({ message: err.message });\n  throw err;\n}","preventionTips":["Check conversation existence before enabling the duplicate action in the UI.","Return 404 from the controller when getConvo returns null.","Ensure the authenticated user owns the conversation before duplicating."],"tags":["conversations","validation","not-found"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}