immich-app/immich · error · BadRequestException
Invalid license key
Error message
Invalid license key
What it means
A BadRequestException (HTTP 400) thrown by UserService.setLicense before any cryptographic verification, when the supplied licenseKey does not begin with either 'IMCL-' (client license) or 'IMSV-' (server license). This is a fast-fail format check on the key prefix.
Source
Thrown at server/src/services/user.service.ts:177
async getLicense(auth: AuthDto): Promise<LicenseResponseDto> {
const metadata = await this.userRepository.getMetadata(auth.user.id);
const license = metadata.find(
(item): item is UserMetadataItem<UserMetadataKey.License> => item.key === UserMetadataKey.License,
);
if (!license) {
throw new NotFoundException();
}
return { ...license.value, activatedAt: new Date(license.value.activatedAt) };
}
async deleteLicense({ user }: AuthDto): Promise<void> {
await this.userRepository.deleteMetadata(user.id, UserMetadataKey.License);
}
async setLicense(auth: AuthDto, license: LicenseKeyDto): Promise<LicenseResponseDto> {
if (!license.licenseKey.startsWith('IMCL-') && !license.licenseKey.startsWith('IMSV-')) {
throw new BadRequestException('Invalid license key');
}
const { licensePublicKey } = this.configRepository.getEnv();
const isClientLicenseValid = this.cryptoRepository.verifySha256(
license.licenseKey,
license.activationKey,
licensePublicKey.client,
);
const isServerLicenseValid = this.cryptoRepository.verifySha256(
license.licenseKey,
license.activationKey,
licensePublicKey.server,
);
if (!isClientLicenseValid && !isServerLicenseValid) {
throw new BadRequestException('Invalid license key');View on GitHub (pinned to 199723261c)
Solutions
- Trim whitespace and verify the key starts with 'IMCL-' or 'IMSV-' before submitting.
- Re-copy the license key from the original purchase/source, ensuring the full string including prefix.
- Separate the license key and activation key into distinct form fields to avoid cross-pasting.
- If the key legitimately lacks the prefix, obtain a correctly formatted key from the issuer.
Example fix
// before
await api.setLicense({ licenseKey: 'ABCD-1234', activationKey: '...' }); // 400
// after
const key = rawKey.trim();
if (!key.startsWith('IMCL-') && !key.startsWith('IMSV-')) {
showFormatError();
return;
}
await api.setLicense({ licenseKey: key, activationKey }); Defensive patterns
Strategy: validation
Validate before calling
function isValidLicenseKeyFormat(key) {
const k = (key ?? '').trim();
return k.startsWith('IMCL-') || k.startsWith('IMSV-');
}
if (!isValidLicenseKeyFormat(licenseKey)) { showFormatError(); return; } Type guard
const hasValidLicensePrefix = (k: string): boolean =>
k.trim().startsWith('IMCL-') || k.trim().startsWith('IMSV-'); Try / catch
try {
await api.setLicense({ licenseKey, activationKey });
} catch (e) {
if ((e as any).status === 400 && (e as any).message === 'Invalid license key') {
setFieldError('licenseKey', 'License key must start with IMCL- or IMSV-');
return;
}
throw e;
} Prevention
- Trim whitespace and check the prefix before submit.
- Keep license key and activation key in separate fields to avoid cross-paste.
- Re-copy the full key from the source if the prefix is missing.
When it happens
Trigger: POST /users/license with a licenseKey that is malformed, missing the prefix, copied with whitespace, or pasted from a source that stripped the prefix. The check happens before signature verification.
Common situations: Typo in the key; user pastes only the activation key field into the license key field; copy-paste includes leading/trailing spaces; key from a different licensing system.
Related errors
- Invalid license key
- Unsupported file type ${filename}
- May not request original file
- Asset not found or asset is not a video
- Quota has been exceeded!
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/b62498a80c340baa.
Report an issue: GitHub.