immich-app/immich · error · Error
Not in maintenance mode
Error message
Not in maintenance mode
What it means
MaintenanceService.createLoginUrl builds a one-time admin login URL for maintenance mode. When called without an explicit secret, it reads the current maintenance-mode state and uses state.secret. If maintenance mode is not currently active, there is no secret to use, so it throws a plain Error 'Not in maintenance mode'. This guards against generating URLs that could never authenticate.
Source
Thrown at server/src/services/maintenance.service.ts:85
);
}
@OnEvent({ name: 'AppRestart', server: true })
onRestart(event: ArgOf<'AppRestart'>, ack?: (ok: 'ok') => void): void {
this.logger.log(`Restarting due to event... ${JSON.stringify(event)}`);
ack?.('ok');
this.appRepository.exitApp();
}
async createLoginUrl(auth: MaintenanceAuthDto, secret?: string): Promise<string> {
const { server } = await this.getConfig({ withCache: true });
const baseUrl = getExternalDomain(server);
if (!secret) {
const state = await this.getMaintenanceMode();
if (!state.isMaintenanceMode) {
throw new Error('Not in maintenance mode');
}
secret = state.secret;
}
return await createMaintenanceLoginUrl(baseUrl, auth, secret);
}
}
View on GitHub (pinned to 199723261c)
Solutions
- Enable maintenance mode first (set isMaintenanceMode true), then call createLoginUrl without a secret.
- Or supply the secret explicitly to createLoginUrl if you hold one from when maintenance mode was enabled.
- Have callers check getMaintenanceMode() before requesting the URL.
- If maintenance ended, use the normal admin login flow instead.
Example fix
// before await maintenanceApi.createLoginUrl(auth); // not in maintenance mode // after await maintenanceApi.setMaintenanceMode(true); await maintenanceApi.createLoginUrl(auth);
Defensive patterns
Strategy: validation
Validate before calling
const state = await api.maintenanceApi.getMaintenanceMode();
if (!state.isMaintenanceMode) {
throw new Error('Enable maintenance mode before requesting a maintenance login URL');
}
await api.maintenanceApi.createLoginUrl(auth); Type guard
const isInMaintenanceMode = (s: { isMaintenanceMode: boolean }) =>
s.isMaintenanceMode === true; Try / catch
try {
return await api.maintenanceApi.createLoginUrl(auth);
} catch (e) {
if (/Not in maintenance mode/.test(String(e?.message))) {
// either enable maintenance mode or pass an explicit secret
} else throw e;
} Prevention
- Check getMaintenanceMode() before requesting the URL.
- Pass an explicit secret if you hold one instead of relying on current state.
- Use the normal admin login outside maintenance windows.
When it happens
Trigger: Calling createLoginUrl(auth, undefined-secret) while getMaintenanceMode().isMaintenanceMode is false. E.g. an admin flow that generates the URL after maintenance mode was already turned off, or a scripted call outside a maintenance window.
Common situations: Race between turning off maintenance mode and a lingering UI action; calling the maintenance login endpoint outside maintenance; automation that does not check mode first.
Related errors
- Forbidden
- User already has a PIN code
- User does not have a PIN code
- Wrong PIN code
- Either password or pinCode is required
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/d925507b9bc64421.
Report an issue: GitHub.