overleaf/overleaf · error

Project ID and history ID are the same for ${projectId} - us

Error message

Project ID and history ID are the same for ${projectId} - use --force to delete anyway

What it means

canDeleteBlob refuses to delete backup blobs when the resolved history id equals the project id. This equality means the blobs are stored under the canonical (correct) path, so deleting them would remove live data, not misplaced backups. The operator must explicitly pass --force to acknowledge the deletion.

Source

Thrown at services/history-v1/storage/scripts/remove_backup_blobs_from_wrong_path.mjs:163

/**
 *
 * @param {string} projectId
 * @param {string} hash
 * @return {Promise<void>}
 */
async function canDeleteBlob(projectId, hash) {
  let historyId
  try {
    historyId = await getHistoryId(projectId)
  } catch (error) {
    if (args.verbose) {
      console.error(error)
    }
    throw new Error(`No history ID found for project ${projectId}, skipping`)
  }
  if (historyId === projectId) {
    throw new Error(
      `Project ID and history ID are the same for ${projectId} - use --force to delete anyway`
    )
  }

  // TODO: fix assert.postgresId to handle integers better and then stop coercing to string below
  assert.postgresId(
    `${historyId}`,
    `History ID ${historyId} does not appear to be for a postgres project`
  )

  try {
    await verifyBlobs(`${historyId}`, [hash])
  } catch (error) {
    if (args.verbose) {
      console.error(error)
    }
    throw new Error(
      `Blob ${hash} is not backed up for project ${projectId} - use --force to delete anyway`

View on GitHub (pinned to 28ad3b03b7)

Solutions

  1. Verify with getHistoryId that this project legitimately has historyId === projectId (legacy project).
  2. Re-run with --force if you are certain the blobs should be deleted.
  3. Exclude such projects from the input list if they are not the target of the cleanup.

Example fix

// before
node remove_backup_blobs_from_wrong_path.mjs --project-id 60f0a1...
// after
node remove_backup_blobs_from_wrong_path.mjs --project-id 60f0a1... --force
Defensive patterns

Strategy: validation

Validate before calling

if (historyId === projectId && !args.force) {
  console.error(`Refusing: historyId === projectId for ${projectId}; pass --force`)
  process.exit(1)
}

Try / catch

try {
  await maybeDeleteBlob(projectId, hash)
} catch (err) {
  if (/use --force to delete anyway/.test(err.message)) {
    console.warn(`Needs --force: ${err.message}`)
  } else throw err
}

Prevention

When it happens

Trigger: The script computes historyId via getHistoryId(projectId) and it is identical to projectId, then canDeleteBlob is invoked without --force.

Common situations: Legacy projects whose history id was always the project id; running the script against a project that was never migrated to the new id scheme; forgetting the --force flag the script's docs recommend for such cases.

Related errors


AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03). Data as JSON: /api/errors/afba8928a0aa7ce9. Report an issue: GitHub.