{"record":{"id":"8700e182a3824cf6","repo":"danny-avila/LibreChat","slug":"latest-messageid-is-required-for-forking-from-ta","errorCode":null,"errorMessage":"Latest `messageId` is required for forking from target message.","messagePattern":"Latest `messageId` is required for forking from target message\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/server/utils/import/fork.js","lineNumber":107,"sourceCode":"  targetMessageId: targetId,\n  requestUserId,\n  newTitle,\n  option = ForkOptions.TARGET_LEVEL,\n  records = false,\n  splitAtTarget = false,\n  latestMessageId,\n  builderFactory = createImportBatchBuilder,\n}) {\n  try {\n    const originalConvo = await getConvo(requestUserId, originalConvoId);\n    let originalMessages = await getMessages({\n      user: requestUserId,\n      conversationId: originalConvoId,\n    });\n\n    let targetMessageId = targetId;\n    if (splitAtTarget && !latestMessageId) {\n      throw new Error('Latest `messageId` is required for forking from target message.');\n    } else if (splitAtTarget) {\n      originalMessages = splitAtTargetLevel(originalMessages, targetId);\n      targetMessageId = latestMessageId;\n    }\n\n    const importBatchBuilder = builderFactory(requestUserId);\n    importBatchBuilder.startConversation(originalConvo.endpoint ?? EModelEndpoint.openAI);\n\n    let messagesToClone = [];\n\n    if (option === ForkOptions.DIRECT_PATH) {\n      // Direct path only\n      messagesToClone = BaseClient.getMessagesForConversation({\n        messages: originalMessages,\n        parentMessageId: targetMessageId,\n      });\n    } else if (option === ForkOptions.INCLUDE_BRANCHES) {\n      // Direct path and siblings","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/utils/import/fork.js#L89-L125","documentation":"Thrown by forkConversation (utils/import/fork.js) when the caller passes splitAtTarget=true but omits latestMessageId. Splitting at a target level requires the latest message id to anchor the new conversation head, so the function refuses to proceed rather than produce a malformed fork.","triggerScenarios":"Calling the fork endpoint with { splitAtTarget: true } but no latestMessageId in the body; a client that only sends targetId assuming the server will derive the latest message; an API client built against older docs that did not require latestMessageId for split mode.","commonSituations":"UI 'fork from here' button wired without passing the currently-selected latest message; partial payload after a refactor; tests exercising splitAtTarget without all required params.","solutions":["When invoking fork with splitAtTarget=true, always include latestMessageId (the messageId of the newest message in the forked branch).","Validate the request at the route layer: if splitAtTarget is true, latestMessageId must be a non-empty string (return 400 otherwise).","If you do not need split semantics, call fork without splitAtTarget (defaults to false) and the requirement disappears."],"exampleFix":"// before\nforkConversation({ requestUserId, originalConvoId, targetId, splitAtTarget: true });\n\n// after\nforkConversation({ requestUserId, originalConvoId, targetId, splitAtTarget: true, latestMessageId });","handlingStrategy":"validation","validationCode":"if (splitAtTarget && !latestMessageId) {\n  throw new Error('Latest `messageId` is required for forking from target message.');\n}","typeGuard":"const canSplitAtTarget = (splitAtTarget, latestMessageId) => !splitAtTarget || typeof latestMessageId === 'string' && latestMessageId.length > 0;","tryCatchPattern":"try {\n  await forkConversation({ requestUserId, originalConvoId, targetId, splitAtTarget, latestMessageId });\n} catch (err) {\n  if (err.message.includes('Latest `messageId` is required')) {\n    return res.status(400).json({ message: err.message });\n  }\n  throw err;\n}","preventionTips":["At the route layer, require latestMessageId whenever splitAtTarget is true.","Pass the currently-selected latest message id from the UI on 'fork from here'.","Write tests covering both splitAtTarget true and false paths."],"tags":["conversations","fork","validation"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}