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
- Verify with getHistoryId that this project legitimately has historyId === projectId (legacy project).
- Re-run with --force if you are certain the blobs should be deleted.
- 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
- Understand legacy projects may have historyId === projectId.
- Always dry-run (no --commit) first.
- Only pass --force after verifying the target is genuinely misplaced backup data.
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
- No history ID found for project ${projectId}, skipping
- Refusing to clear database '${dbName}' in environment '${env
- Blob ${blobHash} not found in project ${historyId}
- Blob ${hash} is not backed up for project ${projectId} - use
- missing --output
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/afba8928a0aa7ce9.
Report an issue: GitHub.