immich-app/immich · critical · Error
Invalid backup file format!
Error message
Invalid backup file format!
What it means
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.
Source
Thrown at server/src/services/database-backup.service.ts:361
toDelete.push(...failedBackups);
for (const file of toDelete) {
await this.storageRepository.unlink(path.join(backupsFolder, file));
}
this.logger.debug(`Database Backup Cleanup Finished, deleted ${toDelete.length} backups`);
}
async restoreDatabaseBackup(
filename: string,
progressCb?: (action: 'backup' | 'restore' | 'migrations' | 'rollback', progress: number) => void,
): Promise<void> {
this.logger.debug(`Database Restore Started`);
let isComplete = false;
try {
if (!isValidDatabaseBackupName(filename)) {
throw new Error('Invalid backup file format!');
}
const backupFilePath = path.join(StorageCore.getBaseFolder(StorageFolder.Backups), filename);
await this.storageRepository.stat(backupFilePath); // => check file exists
let isPgClusterDump = false;
const version = findDatabaseBackupVersion(filename);
if (version && semver.satisfies(version, '<= 2.4')) {
isPgClusterDump = true;
}
const { bin, args, databaseUsername, databasePassword, databaseMajorVersion } =
await this.buildPostgresLaunchArguments('psql', {
singleTransaction: !isPgClusterDump,
});
progressCb?.('backup', 0.05);
View on GitHub (pinned to 199723261c)
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.
Example fix
// before
await backupService.restoreDatabaseBackup(input);
// after
const VALID = /^[\w\d.-]+\.sql(?:\.gz)?$/;
if (!VALID.test(input)) {
throw new Error(`Cannot restore '${input}': not a valid backup filename.`);
}
await backupService.restoreDatabaseBackup(input); Defensive patterns
Strategy: validation
Validate before calling
const VALID = /^[\w\d.-]+\.sql(?:\.gz)?$/;
if (!VALID.test(filename)) {
throw new Error(`'${filename}' is not a valid backup filename.`);
} Type guard
function isValidBackupName(name: string): boolean {
return /^[\w\d.-]+\.sql(?:\.gz)?$/.test(name);
} Prevention
- 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'.
When it happens
Trigger: Triggering a restore with a filename that does not match /^[\w\d.-]+\.sql(?:\.gz)?$/ — wrong extension, special characters, or a path separator.
Common situations: Selecting a non-backup file in a restore UI; passing a relative path instead of just a filename; filename case/extension mismatch.
Related errors
- Invalid backup name!
- Unsupported PostgreSQL version: ${databaseVersion}
- Server health check failed, no admin exists.
- Invalid CLIP dimension size: ${dimSize}
- Invalid environment variables: \n - [${path}] ${issue.messa
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/0f6358324769b132.
Report an issue: GitHub.