immich-app/immich · error · BadRequestException

Invalid license key

Error message

Invalid license key

What it means

Immich requires that a server license key string begins with the literal prefix 'IMSV-'. setLicense() runs this format check BEFORE any cryptographic verification, so the throw at server.service.ts:189 fires purely on string shape. It is a NestJS BadRequestException (HTTP 400) surfaced through the /server/license endpoint.

Source

Thrown at server/src/services/server.service.ts:189

      sidecar: Object.keys(mimeTypes.sidecar),
    };
  }

  async deleteLicense(): Promise<void> {
    await this.systemMetadataRepository.delete(SystemMetadataKey.License);
  }

  async getLicense(): Promise<LicenseResponseDto> {
    const license = await this.systemMetadataRepository.get(SystemMetadataKey.License);
    if (!license) {
      throw new NotFoundException();
    }
    return license;
  }

  async setLicense(dto: LicenseKeyDto): Promise<LicenseResponseDto> {
    if (!dto.licenseKey.startsWith('IMSV-')) {
      throw new BadRequestException('Invalid license key');
    }
    const { licensePublicKey } = this.configRepository.getEnv();
    const isLicenseValid = this.cryptoRepository.verifySha256(
      dto.licenseKey,
      dto.activationKey,
      licensePublicKey.server,
    );
    if (!isLicenseValid) {
      throw new BadRequestException('Invalid license key');
    }

    const licenseData = { ...dto, activatedAt: new Date() };

    await this.systemMetadataRepository.set(SystemMetadataKey.License, licenseData);

    return licenseData;
  }
}

View on GitHub (pinned to 199723261c)

Solutions

  1. Verify the licenseKey value begins exactly with 'IMSV-' (uppercase, hyphen included) before submitting.
  2. Re-copy the full key from the purchase/activation email or portal, trimming any stray whitespace.
  3. Confirm you are using a SERVER license key (IMSV-) and not a key issued for another Immich product.
  4. If the prefix looks correct but the key still came from an unofficial source, obtain a fresh key from the official licensing portal.

Example fix

// before
await api.setLicense({ licenseKey: 'ABC-1234-5678', activationKey: '...' });
// after
await api.setLicense({ licenseKey: 'IMSV-1234-5678', activationKey: '...' });
Defensive patterns

Strategy: validation

Validate before calling

function isValidLicenseKeyFormat(key: string): boolean {
  return typeof key === 'string' && key.startsWith('IMSV-') && key.length > 'IMSV-'.length;
}

// before calling setLicense:
if (!isValidLicenseKeyFormat(dto.licenseKey)) {
  throw new Error('License key must start with "IMSV-".');
}
await serverApi.setLicense(dto);

Type guard

const isLicenseKeyDto = (v: unknown): v is { licenseKey: string; activationKey: string } =>
  !!v && typeof (v as any).licenseKey === 'string' && typeof (v as any).activationKey === 'string';

Try / catch

try {
  await serverApi.setLicense(dto);
} catch (e) {
  if (e instanceof BadRequestException && e.message === 'Invalid license key') {
    showUser('The license key is malformed. It must start with "IMSV-".');
  } else throw e;
}

Prevention

When it happens

Trigger: POST /server/license (ServerInfoService.setLicense via the license controller) with a dto.licenseKey value whose first five characters are not 'IMSV-'. Any leading/trailing whitespace that shifts the prefix also triggers it.

Common situations: Pasting a key clipped mid-string, copying a client/product license key from a different Immich edition, hand-typing the key with a typo, or submitting a key generated for a different product line.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/4381698f6964f958. Report an issue: GitHub.