{"record":{"id":"0f6358324769b132","repo":"immich-app/immich","slug":"invalid-backup-file-format","errorCode":null,"errorMessage":"Invalid backup file format!","messagePattern":"Invalid backup file format!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"server/src/services/database-backup.service.ts","lineNumber":361,"sourceCode":"    toDelete.push(...failedBackups);\n\n    for (const file of toDelete) {\n      await this.storageRepository.unlink(path.join(backupsFolder, file));\n    }\n\n    this.logger.debug(`Database Backup Cleanup Finished, deleted ${toDelete.length} backups`);\n  }\n\n  async restoreDatabaseBackup(\n    filename: string,\n    progressCb?: (action: 'backup' | 'restore' | 'migrations' | 'rollback', progress: number) => void,\n  ): Promise<void> {\n    this.logger.debug(`Database Restore Started`);\n\n    let isComplete = false;\n    try {\n      if (!isValidDatabaseBackupName(filename)) {\n        throw new Error('Invalid backup file format!');\n      }\n\n      const backupFilePath = path.join(StorageCore.getBaseFolder(StorageFolder.Backups), filename);\n      await this.storageRepository.stat(backupFilePath); // => check file exists\n\n      let isPgClusterDump = false;\n      const version = findDatabaseBackupVersion(filename);\n      if (version && semver.satisfies(version, '<= 2.4')) {\n        isPgClusterDump = true;\n      }\n\n      const { bin, args, databaseUsername, databasePassword, databaseMajorVersion } =\n        await this.buildPostgresLaunchArguments('psql', {\n          singleTransaction: !isPgClusterDump,\n        });\n\n      progressCb?.('backup', 0.05);\n","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/database-backup.service.ts#L343-L379","documentation":"Thrown (plain Error) at the start of DatabaseBackupService.restoreDatabaseBackup when isValidDatabaseBackupName(filename) fails. Unlike the upload/download/delete variants (which are 400s), this restore-time check is a hard internal error: you cannot restore from a file whose name is not a recognized SQL/gzip dump.","triggerScenarios":"Triggering a restore with a filename that does not match /^[\\w\\d.-]+\\.sql(?:\\.gz)?$/ — wrong extension, special characters, or a path separator.","commonSituations":"Selecting a non-backup file in a restore UI; passing a relative path instead of just a filename; filename case/extension mismatch.","solutions":["Restore only from files listed by the list-backups endpoint (already validated).","Confirm the extension is '.sql' or '.sql.gz' and the name is ASCII-safe.","Pass the basename only, not a path."],"exampleFix":"// before\nawait backupService.restoreDatabaseBackup(input);\n\n// after\nconst VALID = /^[\\w\\d.-]+\\.sql(?:\\.gz)?$/;\nif (!VALID.test(input)) {\n  throw new Error(`Cannot restore '${input}': not a valid backup filename.`);\n}\nawait backupService.restoreDatabaseBackup(input);","handlingStrategy":"validation","validationCode":"const VALID = /^[\\w\\d.-]+\\.sql(?:\\.gz)?$/;\nif (!VALID.test(filename)) {\n  throw new Error(`'${filename}' is not a valid backup filename.`);\n}","typeGuard":"function isValidBackupName(name: string): boolean {\n  return /^[\\w\\d.-]+\\.sql(?:\\.gz)?$/.test(name);\n}","tryCatchPattern":null,"preventionTips":["Restore only from files surfaced by the list-backups endpoint.","Pass the basename, never a path.","Confirm the extension is exactly '.sql' or '.sql.gz'."],"tags":["database","backup","restore","validation","filename"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}