{"record":{"id":"4381698f6964f958","repo":"immich-app/immich","slug":"invalid-license-key","errorCode":null,"errorMessage":"Invalid license key","messagePattern":"Invalid license key","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/server.service.ts","lineNumber":189,"sourceCode":"      sidecar: Object.keys(mimeTypes.sidecar),\n    };\n  }\n\n  async deleteLicense(): Promise<void> {\n    await this.systemMetadataRepository.delete(SystemMetadataKey.License);\n  }\n\n  async getLicense(): Promise<LicenseResponseDto> {\n    const license = await this.systemMetadataRepository.get(SystemMetadataKey.License);\n    if (!license) {\n      throw new NotFoundException();\n    }\n    return license;\n  }\n\n  async setLicense(dto: LicenseKeyDto): Promise<LicenseResponseDto> {\n    if (!dto.licenseKey.startsWith('IMSV-')) {\n      throw new BadRequestException('Invalid license key');\n    }\n    const { licensePublicKey } = this.configRepository.getEnv();\n    const isLicenseValid = this.cryptoRepository.verifySha256(\n      dto.licenseKey,\n      dto.activationKey,\n      licensePublicKey.server,\n    );\n    if (!isLicenseValid) {\n      throw new BadRequestException('Invalid license key');\n    }\n\n    const licenseData = { ...dto, activatedAt: new Date() };\n\n    await this.systemMetadataRepository.set(SystemMetadataKey.License, licenseData);\n\n    return licenseData;\n  }\n}","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/server.service.ts#L171-L207","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait api.setLicense({ licenseKey: 'ABC-1234-5678', activationKey: '...' });\n// after\nawait api.setLicense({ licenseKey: 'IMSV-1234-5678', activationKey: '...' });","handlingStrategy":"validation","validationCode":"function isValidLicenseKeyFormat(key: string): boolean {\n  return typeof key === 'string' && key.startsWith('IMSV-') && key.length > 'IMSV-'.length;\n}\n\n// before calling setLicense:\nif (!isValidLicenseKeyFormat(dto.licenseKey)) {\n  throw new Error('License key must start with \"IMSV-\".');\n}\nawait serverApi.setLicense(dto);","typeGuard":"const isLicenseKeyDto = (v: unknown): v is { licenseKey: string; activationKey: string } =>\n  !!v && typeof (v as any).licenseKey === 'string' && typeof (v as any).activationKey === 'string';","tryCatchPattern":"try {\n  await serverApi.setLicense(dto);\n} catch (e) {\n  if (e instanceof BadRequestException && e.message === 'Invalid license key') {\n    showUser('The license key is malformed. It must start with \"IMSV-\".');\n  } else throw e;\n}","preventionTips":["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."],"tags":["license","validation","server","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}