immich-app/immich · error · UnauthorizedException

Missing JWT Token

Error message

Missing JWT Token

What it means

The maintenance worker's login() method requires a maintenance JWT string; if the argument is absent or empty it throws UnauthorizedException('Missing JWT Token') before any verification is attempted. It is the guard clause distinguishing 'no token supplied' from the separate 'Invalid JWT Token' failure in the jwtVerify catch block.

Solutions

  1. Perform a maintenance login first and pass the returned token into login()/authenticate.
  2. Attach the JWT in the request (Authorization: Bearer <token> or the maintenance cookie) before calling protected maintenance endpoints.
  3. Check proxy/middleware configuration so the Authorization header is forwarded to Immich.
  4. Confirm the client sends the correct field the controller reads (e.g. token in MaintenanceLoginDto body), not a missing/renamed property.

Example fix

// before
await maintenanceWorker.login(); // UnauthorizedException: Missing JWT Token
// after
if (!jwt) throw new Error('Login first to obtain a maintenance token');
await maintenanceWorker.login(jwt);
Defensive patterns

Strategy: validation

Validate before calling

if (typeof jwt !== 'string' || jwt.length === 0) {
  throw new Error('A maintenance JWT is required; perform a maintenance login first');
}

Type guard

function hasJwt(t: string | undefined | null): t is string {
  return typeof t === 'string' && t.length > 0;
}

Prevention

When it happens

Trigger: Calling maintenanceWorkerService.login() (directly or via the authenticate/status callers) with jwt === undefined or an empty string; sending a maintenance login request with no Authorization header / no token parameter so no JWT is passed through.

Common situations: Client forgot to attach the maintenance token obtained from a prior login; header stripped by a reverse proxy; calling the status/authenticate path before ever performing a maintenance login; passing the wrong field name so the token never reaches the handler.

Related errors


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

Appendix: source

Thrown at server/src/maintenance/maintenance-worker.service.ts:262

    return this.login(jwtToken);
  }

  async status(potentiallyJwt?: string): Promise<MaintenanceStatusResponseDto> {
    try {
      await this.login(potentiallyJwt);
      return this.getStatus();
    } catch {
      return this.getPublicStatus();
    }
  }

  detectPriorInstall(): Promise<MaintenanceDetectInstallResponseDto> {
    return detectPriorInstall(this.storageRepository);
  }

  async login(jwt?: string): Promise<MaintenanceAuthDto> {
    if (!jwt) {
      throw new UnauthorizedException('Missing JWT Token');
    }

    try {
      const result = await jwtVerify<MaintenanceAuthDto>(jwt, new TextEncoder().encode(this.secret));
      return result.payload;
    } catch {
      throw new UnauthorizedException('Invalid JWT Token');
    }
  }

  async setAction(action: SetMaintenanceModeDto) {
    this.setStatus({
      active: true,
      action: action.action,
    });

    await this.runAction(action);
  }

View on GitHub (pinned to e55ac299a4)