immich-app/immich · critical · Error
Server health check failed, no admin exists.
Error message
Server health check failed, no admin exists.
What it means
Thrown (plain Error) inside DatabaseBackupService.restoreDatabaseBackup after migrations run. As a post-restore health check it asserts userRepository.hasAdmin() is true; an empty (no-admin) restored DB means the restore did not yield a usable system, so it triggers the rollback path (restoring the pre-restore snapshot).
Source
Thrown at server/src/services/database-backup.service.ts:420
const [progressSource, progressSink] = createSqlProgressStreams((progress) => {
if (isComplete) {
return;
}
this.logger.log(`Restore progress ~ ${(progress * 100).toFixed(2)}%`);
progressCb?.('restore', progress);
});
await pipeline(sqlStream, createSqlOwnerTransformStream(databaseUsername), progressSource, psql, progressSink);
try {
progressCb?.('migrations', 0.9);
await this.databaseRepository.runMigrations();
const hasAdmin = await this.userRepository.hasAdmin();
if (!hasAdmin) {
throw new Error('Server health check failed, no admin exists.');
}
await this.maintenanceHealthRepository.checkApiHealth();
} catch (error) {
progressCb?.('rollback', 0);
const fileStream = this.storageRepository.createPlainReadStream(restorePointFilePath);
const gunzip = this.storageRepository.createGunzip();
fileStream.pipe(gunzip);
inputStream = gunzip;
const sqlStream = Readable.from(sqlRollback(inputStream, databaseUsername));
const psql = this.processRepository.spawnDuplexStream(bin, args, {
env: {
PATH: process.env.PATH,
PGPASSWORD: databasePassword,
},
});View on GitHub (pinned to 199723261c)
Solutions
- Restore from a known-good backup that was taken from a fully set-up instance (with an admin user).
- If no such backup exists, start fresh, complete onboarding to create an admin, then take a backup.
- Inspect the dump before restoring to confirm the users table contains an isAdmin=true row.
Example fix
// before
await backupService.restoreDatabaseBackup(file);
// after
// Validate the source dump is non-empty and contains an admin before attempting restore.
const preview = await inspectDump(path.join(BACKUP_DIR, file));
if (!preview.hasAdminUser) {
throw new Error('Refusing to restore: backup contains no admin user; pick a complete backup.');
}
await backupService.restoreDatabaseBackup(file); Defensive patterns
Strategy: fallback
Validate before calling
// Pre-flight: confirm the dump contains an admin before restoring.
const preview = await inspectDump(path.join(BACKUP_DIR, filename));
if (!preview.hasAdminUser) {
throw new Error('Backup has no admin user; refusing restore.');
} Try / catch
try {
await backupService.restoreDatabaseBackup(filename, onProgress);
} catch (e) {
if (e instanceof Error && e.message.includes('no admin exists')) {
// service already rolled back to the snapshot; surface a clear message
throw new Error('Restore failed: backup contained no admin; rolled back to previous state.');
}
throw e;
} Prevention
- Only restore backups taken from a fully on boarded instance.
- Inspect the dump's users table for an admin row before restoring.
- Keep a pre-restore snapshot (the service does this) and verify rollback succeeds.
When it happens
Trigger: Restoring a backup that contains no admin user — e.g. a partial/empty dump, a dump of the wrong database, or a backup taken before any admin existed.
Common situations: Restoring a dump from a non-Immich or empty schema; restoring a backup of a fresh DB that never had an admin; the migrations ran but the users table is empty.
Related errors
- Unsupported PostgreSQL version: ${databaseVersion}
- Invalid backup file format!
- Invalid backup name!
- No vector extension found. Available extensions: ${VECTOR_EX
- ${EXTENSION_NAMES[extension]} extension is not installed
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/019628975cfc3f82.
Report an issue: GitHub.