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
- Verify the licenseKey value begins exactly with 'IMSV-' (uppercase, hyphen included) before submitting.
- Re-copy the full key from the purchase/activation email or portal, trimming any stray whitespace.
- Confirm you are using a SERVER license key (IMSV-) and not a key issued for another Immich product.
- 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
- Validate the 'IMSV-' prefix on the client before enabling submit.
- Copy keys from the official activation record; avoid hand-typing.
- Trim whitespace from pasted keys in the UI.
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
- Not Found
- Invalid license key
- Unsupported file type ${filename}
- May not request original file
- Asset not found or asset is not a video
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/4381698f6964f958.
Report an issue: GitHub.