{"record":{"id":"1cb70c7d78572935","repo":"immich-app/immich","slug":"admin-setup-is-not-available","errorCode":null,"errorMessage":"Admin setup is not available","messagePattern":"Admin setup is not available","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/base.service.ts","lineNumber":291,"sourceCode":"    return updateConfig(this.configRepos, newConfig);\n  }\n\n  requireAccess(request: AccessRequest) {\n    return requireAccess(this.accessRepository, request);\n  }\n\n  checkAccess(request: AccessRequest) {\n    return checkAccess(this.accessRepository, request);\n  }\n\n  async isSetupAvailable(): Promise<boolean> {\n    const { setup } = this.configRepository.getEnv();\n    return setup.allow && !(await this.userRepository.hasAdmin());\n  }\n\n  async requireSetupAvailable(): Promise<void> {\n    if (!(await this.isSetupAvailable())) {\n      throw new BadRequestException('Admin setup is not available');\n    }\n  }\n\n  async createUser(dto: Insertable<UserTable> & { email: string }): Promise<UserAdmin> {\n    const exists = await this.userRepository.getByEmail(dto.email);\n    if (exists) {\n      this.logger.debug('User creation rejected: user already exists');\n      throw new BadRequestException('Email is not available');\n    }\n\n    if (!dto.isAdmin) {\n      const localAdmin = await this.userRepository.getAdmin();\n      if (!localAdmin) {\n        throw new BadRequestException('The first registered account must the administrator.');\n      }\n    }\n\n    const payload: Insertable<UserTable> = { ...dto };","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/base.service.ts#L273-L309","documentation":"Thrown by BaseService.requireSetupAvailable. Setup is allowed only when configRepository.getEnv().setup.allow is true AND no admin user exists yet (userRepository.hasAdmin() is false). If either condition fails, initial admin registration is closed.","triggerScenarios":"Calling the admin-setup/registration endpoint after an admin already exists, or when the environment explicitly disabled setup (setup.allow = false).","commonSituations":"Hitting the onboarding flow a second time after initial setup completed; a deployment flag/CLI arg disabled setup; an imported backup already contained an admin user.","solutions":["Call isSetupAvailable() first and only expose the setup UI when it returns true.","If re-onboarding is genuinely intended, remove/disable the existing admin (or restore an empty DB) so hasAdmin() returns false.","Check that the env/CLI configuration that gates setup.allow is set as intended for this deployment."],"exampleFix":"// before\nawait userService.requireSetupAvailable();\nawait userService.createUser(dto);\n\n// after\nif (!(await userService.isSetupAvailable())) {\n  throw new BadRequestException('Setup already complete or disabled in this environment.');\n}\nawait userService.createUser(dto);","handlingStrategy":"validation","validationCode":"if (!(await userService.isSetupAvailable())) {\n  // hide the setup screen / return early instead of calling requireSetupAvailable()\n  return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate the setup UI on isSetupAvailable() so it is only reachable when onboarding is open.","Document that setup.allow can be disabled via env/CLI for locked-down deployments.","After a DB restore that includes an admin, expect setup to be permanently closed."],"tags":["setup","admin","onboarding","bad-request"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}