{"record":{"id":"019628975cfc3f82","repo":"immich-app/immich","slug":"server-health-check-failed-no-admin-exists","errorCode":null,"errorMessage":"Server health check failed, no admin exists.","messagePattern":"Server health check failed, no admin exists\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/database-backup.service.ts","lineNumber":429,"sourceCode":"      const [progressSource, progressSink] = createSqlProgressStreams((progress) => {\n        if (isComplete) {\n          return;\n        }\n\n        this.logger.log(`Restore progress ~ ${(progress * 100).toFixed(2)}%`);\n        progressCb?.('restore', progress);\n      });\n\n      await pipeline(sqlStream, createSqlOwnerTransformStream(databaseUsername), progressSource, psql, progressSink);\n\n      try {\n        progressCb?.('migrations', 0.9);\n\n        await this.databaseRepository.runMigrations();\n\n        const hasAdmin = await this.userRepository.hasAdmin();\n        if (!hasAdmin) {\n          throw new Error('Server health check failed, no admin exists.');\n        }\n\n        await this.maintenanceHealthRepository.checkApiHealth();\n      } catch (error) {\n        progressCb?.('rollback', 0);\n\n        const fileStream = this.storageRepository.createPlainReadStream(restorePointFilePath);\n        const gunzip = this.storageRepository.createGunzip();\n        fileStream.pipe(gunzip);\n        inputStream = gunzip;\n\n        const sqlStream = Readable.from(sqlRollback(inputStream, databaseUsername));\n        const psql = this.processRepository.spawnDuplexStream(bin, args, {\n          env: {\n            PATH: process.env.PATH,\n            PGPASSWORD: databasePassword,\n          },\n        });","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/database-backup.service.ts#L411-L447","documentation":"After restoring a database backup, the service runs migrations and then performs a health check that requires at least one admin user to exist. If userRepository.hasAdmin() returns false, the restore is considered failed (thrown inside the try block, so a rollback is triggered) because a backup without an admin account cannot produce a usable server.","triggerScenarios":"Restoring a database dump that contains no admin user — e.g. a backup taken before initial setup, an empty/partial dump, or a dump from a fresh database where migrations ran but the setup wizard was never completed.","commonSituations":"Restoring backups copied from another instance's pre-setup state; manually imported SQL dumps; backups from test environments with no registered user.","solutions":["Restore a backup taken from a fully initialized Immich instance (setup completed, admin created).","Register an admin user after restore, or re-restore with a complete backup.","Verify the dump includes the users table with an admin entry before restoring."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const users = await api.getAllUsers();\nif (!users.some((u) => u.isAdmin)) throw new Error('Backup has no admin user; restore would fail');","typeGuard":null,"tryCatchPattern":"try {\n  await api.restoreDatabaseBackup(filename);\n} catch (e) {\n  if (/no admin exists/.test(e.message)) {\n    console.error('Backup predates admin creation; restore a complete backup and re-run setup.');\n  } else throw e;\n}","preventionTips":["Only back up instances that have completed initial setup (admin registered).","After any restore, verify an admin user exists before relying on the server.","Avoid hand-edited or partial SQL dumps for restore."],"tags":["backup","restore","health-check"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}