danny-avila/LibreChat · error · Error

Latest `messageId` is required for forking from target messa

Error message

Latest `messageId` is required for forking from target message.

What it means

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.

Source

Thrown at api/server/utils/import/fork.js:107

  targetMessageId: targetId,
  requestUserId,
  newTitle,
  option = ForkOptions.TARGET_LEVEL,
  records = false,
  splitAtTarget = false,
  latestMessageId,
  builderFactory = createImportBatchBuilder,
}) {
  try {
    const originalConvo = await getConvo(requestUserId, originalConvoId);
    let originalMessages = await getMessages({
      user: requestUserId,
      conversationId: originalConvoId,
    });

    let targetMessageId = targetId;
    if (splitAtTarget && !latestMessageId) {
      throw new Error('Latest `messageId` is required for forking from target message.');
    } else if (splitAtTarget) {
      originalMessages = splitAtTargetLevel(originalMessages, targetId);
      targetMessageId = latestMessageId;
    }

    const importBatchBuilder = builderFactory(requestUserId);
    importBatchBuilder.startConversation(originalConvo.endpoint ?? EModelEndpoint.openAI);

    let messagesToClone = [];

    if (option === ForkOptions.DIRECT_PATH) {
      // Direct path only
      messagesToClone = BaseClient.getMessagesForConversation({
        messages: originalMessages,
        parentMessageId: targetMessageId,
      });
    } else if (option === ForkOptions.INCLUDE_BRANCHES) {
      // Direct path and siblings

View on GitHub (pinned to 5ff282f900)

Solutions

  1. When invoking fork with splitAtTarget=true, always include latestMessageId (the messageId of the newest message in the forked branch).
  2. Validate the request at the route layer: if splitAtTarget is true, latestMessageId must be a non-empty string (return 400 otherwise).
  3. If you do not need split semantics, call fork without splitAtTarget (defaults to false) and the requirement disappears.

Example fix

// before
forkConversation({ requestUserId, originalConvoId, targetId, splitAtTarget: true });

// after
forkConversation({ requestUserId, originalConvoId, targetId, splitAtTarget: true, latestMessageId });
Defensive patterns

Strategy: validation

Validate before calling

if (splitAtTarget && !latestMessageId) {
  throw new Error('Latest `messageId` is required for forking from target message.');
}

Type guard

const canSplitAtTarget = (splitAtTarget, latestMessageId) => !splitAtTarget || typeof latestMessageId === 'string' && latestMessageId.length > 0;

Try / catch

try {
  await forkConversation({ requestUserId, originalConvoId, targetId, splitAtTarget, latestMessageId });
} catch (err) {
  if (err.message.includes('Latest `messageId` is required')) {
    return res.status(400).json({ message: err.message });
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/8700e182a3824cf6. Report an issue: GitHub.