danny-avila/LibreChat · error · Error

Conversation not found

Error message

Conversation not found

What it means

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.

Source

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

    return {
      conversation,
      messages,
    };
  });
}

/**
 * Duplicates a conversation and all its messages.
 * @param {object} params - The parameters for duplicating the conversation.
 * @param {string} params.userId - The ID of the user duplicating the conversation.
 * @param {string} params.conversationId - The ID of the conversation to duplicate.
 * @param {string} [params.title] - Optional title override for the duplicate.
 * @returns {Promise<{ conversation: TConversation, messages: TMessage[] }>} The duplicated conversation and messages.
 */
async function duplicateConversation({ userId, conversationId, title }) {
  const originalConvo = await getConvo(userId, conversationId);
  if (!originalConvo) {
    throw new Error('Conversation not found');
  }

  const originalMessages = await getMessages({
    user: userId,
    conversationId,
  });

  const messagesToClone = getMessagesUpToTargetLevel(
    originalMessages,
    originalMessages[originalMessages.length - 1].messageId,
  );

  const importBatchBuilder = createImportBatchBuilder(userId);
  importBatchBuilder.startConversation(originalConvo.endpoint ?? EModelEndpoint.openAI);

  cloneMessagesWithTimestamps(messagesToClone, importBatchBuilder);

  const duplicateTitle = title || originalConvo.title;

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Verify the conversationId exists for the user (e.g. via a presence check or by refreshing the source list) before offering the duplicate action.
  2. Return a 404 from the controller when getConvo yields null, instead of letting the generic error propagate.
  3. Confirm the authenticated user matches the conversation's owner.

Example fix

// before
await duplicateConversation({ userId, conversationId });

// after
const existing = await getConvo(userId, conversationId);
if (!existing) return res.status(404).json({ message: 'Conversation not found' });
await duplicateConversation({ userId, conversationId });
Defensive patterns

Strategy: validation

Validate before calling

const originalConvo = await getConvo(userId, conversationId);
if (!originalConvo) {
  throw new Error('Conversation not found');
}

Type guard

const conversationExistsForUser = async (userId, conversationId) => !!(await getConvo(userId, conversationId));

Try / catch

try {
  await duplicateConversation({ userId, conversationId });
} catch (err) {
  if (err.message === 'Conversation not found') return res.status(404).json({ message: err.message });
  throw err;
}

Prevention

When it happens

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

Common situations: Duplicate action on an already-deleted conversation; race between deletion and duplicate; misrouted request after a user switch; tests with fabricated ids.

Related errors


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