immich-app/immich · error · Error

Failed to fetch activation key

Error message

Failed to fetch activation key

What it means

getActivationKey() fetches a license activation key from PUBLIC_IMMICH_PAY_HOST (/api/v1activate/<licenseKey>) and throws if the HTTP response is not ok. This means the license-purchase service rejected the request — bad license key, network failure, or service error — so the license cannot be activated client-side.

Solutions

  1. Verify the license key is copied exactly (no extra whitespace) and is unused/not expired.
  2. Check network reachability of the payment host (disable ad-blockers/VPN blocking it) and retry.
  3. Confirm your immich version's activation flow matches the hosted service; update the app if outdated.
  4. If the service is down, retry later or contact Immich support with your purchase details.
  5. Inspect the HTTP status of the fetch response to distinguish 404 (bad key) from 5xx (service issue).

Example fix

// before
const key = await getActivationKey('  IM-XXXX  '); // whitespace-corrupted key
// after
const key = await getActivationKey(licenseKey.trim());
Defensive patterns

Strategy: try-catch

Validate before calling

if (!licenseKey || licenseKey.trim().length === 0) throw new ValidationError('License key is required');
if (typeof PUBLIC_IMMICH_PAY_HOST !== 'string' || !PUBLIC_IMMICH_PAY_HOST.startsWith('https://')) throw new ConfigError('Bad activation host');

Try / catch

try { key = await getActivationKey(licenseKey.trim()); } catch (e) { if (e.message === 'Failed to fetch activation key') showToast(t('license.activation_failed')); else throw e; }

Prevention

When it happens

Trigger: Calling getActivationKey(licenseKey) (from the license activation flow) when the remote activation endpoint returns 4xx/5xx or the fetch otherwise yields !response.ok.

Common situations: Entering a mistyped or already-used license key; PUBLIC_IMMICH_PAY_HOST unreachable (firewall/ad-blocker/ VPN); immich pay service downtime; server key generated by an incompatible version.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/d67e33703ac246e2. Report an issue: GitHub.

Appendix: source

Thrown at web/src/lib/utils/license-utils.ts:20

import { PUBLIC_IMMICH_BUY_HOST, PUBLIC_IMMICH_PAY_HOST } from '$env/static/public';
import type { ImmichProduct } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';

export const activateProduct = async (licenseKey: string, activationKey: string): Promise<LicenseResponseDto> => {
  // TODO is this needed?
  await authManager.load();

  const isServerActivation = authManager.user.isAdmin && licenseKey.search('IMSV') !== -1;
  const licenseKeyDto = { licenseKey, activationKey };
  // Send server key to user activation if user is not admin
  return isServerActivation ? setServerLicense({ licenseKeyDto }) : setUserLicense({ licenseKeyDto });
};

export const getActivationKey = async (licenseKey: string): Promise<string> => {
  const response = await fetch(new URL(`/api/v1/activate/${licenseKey}`, PUBLIC_IMMICH_PAY_HOST).href);
  if (!response.ok) {
    throw new Error('Failed to fetch activation key');
  }
  return response.text();
};

export const getLicenseLink = (license: ImmichProduct) => {
  const url = new URL('/', PUBLIC_IMMICH_BUY_HOST);
  url.searchParams.append('productId', license);
  url.searchParams.append('instanceUrl', serverConfigManager.value.externalDomain || globalThis.origin);
  return url.href;
};

View on GitHub (pinned to e55ac299a4)