immich-app/immich · info · NotFoundException

Not Found

Error message

Not Found

What it means

Thrown by ServerService.getLicense when systemMetadataRepository.get(SystemMetadataKey.License) returns null. The server has no license key stored in system metadata. NotFoundException with no message -> HTTP 404 'Not Found'. Used by the license check endpoint to signal 'no license configured'.

Source

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

    return serverStats;
  }

  getSupportedMediaTypes(): ServerMediaTypesResponseDto {
    return {
      video: Object.keys(mimeTypes.video),
      image: Object.keys(mimeTypes.image),
      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');
    }

View on GitHub (pinned to 199723261c)

Solutions

  1. Activate a license via POST/PUT /server/license (setLicense) before querying it.
  2. Treat 404 from this endpoint as 'no license configured' (not an error) in the client.
  3. Add a message to the NotFoundException so clients can distinguish from a generic 404.

Example fix

// before
const license = await this.systemMetadataRepository.get(SystemMetadataKey.License);
if (!license) {
  throw new NotFoundException();
}

// after
const license = await this.systemMetadataRepository.get(SystemMetadataKey.License);
if (!license) {
  throw new NotFoundException('No license configured');
}

// client-side
try {
  return await api.get('/server/license');
} catch (e) {
  if (e.status === 404) return null; // no license set
  throw e;
}
Defensive patterns

Strategy: validation

Validate before calling

// Check whether a license is configured before reading it.
const license = await systemMetadataRepository.get(SystemMetadataKey.License).catch(() => null);
if (!license) {
  // no license configured; prompt admin to activate one
  return null;
}
return license;

Type guard

const hasLicense = (l: LicenseResponseDto | null | undefined): l is LicenseResponseDto =>
  !!l && typeof l.licenseKey === 'string';

Try / catch

try {
  return await serverService.getLicense();
} catch (e) {
  if (e instanceof NotFoundException) {
    // no license configured yet; not an error
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /server/license (or the license-view endpoint) on a server that has never had a license set, or whose license was deleted via deleteLicense.

Common situations: Fresh install; admin cleared the license; license was set on a different instance; checking license status before activation.

Related errors


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