immich-app/immich · error · BadRequestException

Admin setup is not available

Error message

Admin setup is not available

What it means

requireSetupAvailable checks that the server's setup flag is enabled (allow) and that no admin user exists yet (userRepository.hasAdmin). Admin-creation/setup endpoints call it first; once setup is done or disallowed, any attempt throws BadRequestException('Admin setup is not available').

Solutions

  1. Do not call the setup endpoint again — log in with the existing admin account
  2. Reset admin credentials via the admin CLI/user management instead of setup
  3. If setup was disallowed by config, enable it in the server configuration only for intentional re-init
  4. Verify the correct database; a restored DB may already contain an admin

Example fix

// before
await api.post('/users/admin', adminDto); // setup already done
// after
await api.post('/auth/login', { email, password }); // existing admin
Defensive patterns

Strategy: try-catch

Validate before calling

const hasAdmin = await userRepository.hasAdmin(); if (hasAdmin) throw new Error('setup already completed');

Try / catch

catch (e) { if (e.status === 400 && /setup is not available/.test(e.message)) { /* login with existing admin instead */ } }

Prevention

When it happens

Trigger: POST to the admin registration/setup endpoint after an admin already exists, or when server config disables setup.

Common situations: Re-running the initial setup wizard on an already-initialized instance; replaying setup requests from automation; IMMICH_CONFIG setup.allow disabled in a new deployment; database restored with existing users.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/1cb70c7d78572935. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/base.service.ts:299

    return updateConfig(this.configRepos, newConfig);
  }

  requireAccess(request: AccessRequest) {
    return requireAccess(this.accessRepository, request);
  }

  checkAccess(request: AccessRequest) {
    return checkAccess(this.accessRepository, request);
  }

  async isSetupAvailable(): Promise<boolean> {
    const { setup } = this.configRepository.getEnv();
    return setup.allow && !(await this.userRepository.hasAdmin());
  }

  async requireSetupAvailable(): Promise<void> {
    if (!(await this.isSetupAvailable())) {
      throw new BadRequestException('Admin setup is not available');
    }
  }

  async createUser(dto: Omit<Insertable<UserTable>, 'clusterGroupId'> & { email: string }): Promise<UserAdmin> {
    const exists = await this.userRepository.getByEmail(dto.email);
    if (exists) {
      this.logger.debug('User creation rejected: user already exists');
      throw new BadRequestException('Email is not available');
    }

    if (!dto.isAdmin) {
      const localAdmin = await this.userRepository.getAdmin();
      if (!localAdmin) {
        throw new BadRequestException('The first registered account must the administrator.');
      }
    }

    const payload: Omit<Insertable<UserTable>, 'clusterGroupId'> = { ...dto };

View on GitHub (pinned to e55ac299a4)