{"record":{"id":"d67e33703ac246e2","repo":"immich-app/immich","slug":"failed-to-fetch-activation-key","errorCode":null,"errorMessage":"Failed to fetch activation key","messagePattern":"Failed to fetch activation key","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/lib/utils/license-utils.ts","lineNumber":20,"sourceCode":"import { PUBLIC_IMMICH_BUY_HOST, PUBLIC_IMMICH_PAY_HOST } from '$env/static/public';\nimport type { ImmichProduct } from '$lib/constants';\nimport { authManager } from '$lib/managers/auth-manager.svelte';\nimport { serverConfigManager } from '$lib/managers/server-config-manager.svelte';\n\nexport const activateProduct = async (licenseKey: string, activationKey: string): Promise<LicenseResponseDto> => {\n  // TODO is this needed?\n  await authManager.load();\n\n  const isServerActivation = authManager.user.isAdmin && licenseKey.search('IMSV') !== -1;\n  const licenseKeyDto = { licenseKey, activationKey };\n  // Send server key to user activation if user is not admin\n  return isServerActivation ? setServerLicense({ licenseKeyDto }) : setUserLicense({ licenseKeyDto });\n};\n\nexport const getActivationKey = async (licenseKey: string): Promise<string> => {\n  const response = await fetch(new URL(`/api/v1/activate/${licenseKey}`, PUBLIC_IMMICH_PAY_HOST).href);\n  if (!response.ok) {\n    throw new Error('Failed to fetch activation key');\n  }\n  return response.text();\n};\n\nexport const getLicenseLink = (license: ImmichProduct) => {\n  const url = new URL('/', PUBLIC_IMMICH_BUY_HOST);\n  url.searchParams.append('productId', license);\n  url.searchParams.append('instanceUrl', serverConfigManager.value.externalDomain || globalThis.origin);\n  return url.href;\n};\n","sourceCodeStart":2,"sourceCodeEnd":31,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/web/src/lib/utils/license-utils.ts#L2-L31","documentation":"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.","triggerScenarios":"Calling getActivationKey(licenseKey) (from the license activation flow) when the remote activation endpoint returns 4xx/5xx or the fetch otherwise yields !response.ok.","commonSituations":"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.","solutions":["Verify the license key is copied exactly (no extra whitespace) and is unused/not expired.","Check network reachability of the payment host (disable ad-blockers/VPN blocking it) and retry.","Confirm your immich version's activation flow matches the hosted service; update the app if outdated.","If the service is down, retry later or contact Immich support with your purchase details.","Inspect the HTTP status of the fetch response to distinguish 404 (bad key) from 5xx (service issue)."],"exampleFix":"// before\nconst key = await getActivationKey('  IM-XXXX  '); // whitespace-corrupted key\n// after\nconst key = await getActivationKey(licenseKey.trim());","handlingStrategy":"try-catch","validationCode":"if (!licenseKey || licenseKey.trim().length === 0) throw new ValidationError('License key is required');\nif (typeof PUBLIC_IMMICH_PAY_HOST !== 'string' || !PUBLIC_IMMICH_PAY_HOST.startsWith('https://')) throw new ConfigError('Bad activation host');","typeGuard":null,"tryCatchPattern":"try { key = await getActivationKey(licenseKey.trim()); } catch (e) { if (e.message === 'Failed to fetch activation key') showToast(t('license.activation_failed')); else throw e; }","preventionTips":["Trim and validate license keys before activation","Check ad-blocker/VPN interference with the payment host","Handle non-ok responses with status-specific messaging for support","Retry activation on 5xx since the remote service may be temporarily down"],"tags":["license","http","network","activation"],"backgroundTag":"http-request-failed","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}