immich-app/immich · error · BadRequestException

Invalid backup name!

Error message

Invalid backup name!

What it means

Thrown by DatabaseBackupService.uploadBackup (BadRequestException). The uploaded file's basename must match /^\d\w.-]+\.sql(?:\.gz)?$/: only word characters, digits, hyphens and dots, ending in '.sql' or '.sql.gz'. Any other name is rejected before the file is written to the backups folder.

Source

Thrown at server/src/services/database-backup.service.ts:265

      await this.storageRepository.rename(temporaryFilePath, backupFilePath);
    } catch (error) {
      this.logger.error(`Database Backup Failure: ${error}`);
      await this.storageRepository
        .unlink(temporaryFilePath)

        .catch((error) => this.logger.error(`Failed to delete failed backup file: ${error}`));
      throw error;
    }

    this.logger.log(`Database Backup Success`);
    return backupFilePath;
  }

  async uploadBackup(file: Express.Multer.File): Promise<void> {
    const backupsFolder = StorageCore.getBaseFolder(StorageFolder.Backups);
    const fn = basename(file.originalname);
    if (!isValidDatabaseBackupName(fn)) {
      throw new BadRequestException('Invalid backup name!');
    }

    const filePath = path.join(backupsFolder, `uploaded-${fn}`);
    await this.storageRepository.createOrOverwriteFile(filePath, file.buffer);
  }

  downloadBackup(fileName: string): ImmichFileResponse {
    if (!isValidDatabaseBackupName(fileName)) {
      throw new BadRequestException('Invalid backup name!');
    }

    const filePath = path.join(StorageCore.getBaseFolder(StorageFolder.Backups), fileName);

    return {
      path: filePath,
      fileName,
      cacheControl: CacheControl.PrivateWithoutCache,
      contentType: fileName.endsWith('.gz') ? 'application/gzip' : 'application/sql',

View on GitHub (pinned to 199723261c)

Solutions

  1. Rename the file to match <name>.sql.gz (or .sql), ASCII only, no spaces.
  2. If the file is gzipped, ensure the extension is exactly '.sql.gz'.
  3. Validate the filename client-side before upload using the same regex.

Example fix

// before
const fd = new FormData(); fd.append('file', rawFile); await upload(fd);

// after
const VALID = /^[\w\d.-]+\.sql(?:\.gz)?$/;
if (!VALID.test(rawFile.name)) {
  throw new Error(`Backup filename must match ${VALID}`);
}
const fd = new FormData(); fd.append('file', rawFile); await upload(fd);
Defensive patterns

Strategy: type-guard

Validate before calling

const VALID = /^[\w\d.-]+\.sql(?:\.gz)?$/;
if (!VALID.test(file.originalname)) {
  throw new BadRequestException('Backup must be named <name>.sql or <name>.sql.gz');
}

Type guard

function isValidBackupName(name: string): boolean {
  return /^[\w\d.-]+\.sql(?:\.gz)?$/.test(name);
}

Prevention

When it happens

Trigger: Uploading a backup whose original filename contains spaces, path separators, unusual extensions (e.g. .zip, .bak, .dump), or lacks the .sql/.sql.gz suffix.

Common situations: User renames a dump to something descriptive ('My Backup July.sql'); zipped/tarred dump (.zip); filename with spaces or unicode; case issues like '.SQL'.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/9e5a44a68f9049a7. Report an issue: GitHub.