{"record":{"id":"08489fcc5e7a0c3d","repo":"Budibase/budibase","slug":"offline-license-does-not-match-this-installation","errorCode":null,"errorMessage":"Offline license does not match this installation","messagePattern":"Offline license does not match this installation","errorType":"exception","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/pro/src/sdk/licensing/licenses/offline/offline.ts","lineNumber":122,"sourceCode":"): Promise<OfflineLicense> {\n  let license: OfflineLicense\n  try {\n    license = await signing.verifyLicenseToken(token)\n  } catch {\n    throw new HTTPError(\"Invalid offline license token\", 400)\n  }\n\n  try {\n    verifyExpiry(license)\n  } catch {\n    throw new HTTPError(\"Offline license has expired\", 400)\n  }\n\n  try {\n    await verifyInstallation(license)\n  } catch (e) {\n    if (e instanceof OfflineLicenseMismatchError) {\n      throw new HTTPError(\n        \"Offline license does not match this installation\",\n        400\n      )\n    }\n    throw e\n  }\n\n  return license\n}\n\nexport async function getOfflineLicense(): Promise<License | undefined> {\n  try {\n    const token = await getOfflineLicenseToken()\n    if (token) {\n      const license = await verifyOfflineLicenseToken(token)\n      return enrichLicense(license)\n    }\n  } catch (e) {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/pro/src/sdk/licensing/licenses/offline/offline.ts#L104-L140","documentation":"verifyOfflineLicenseToken calls verifyInstallation and, when it throws OfflineLicenseMismatchError, rethrows it as HTTPError('Offline license does not match this installation', 400). The license's signed identifier (installId, unique tenantId) doesn't match the current installation, so the token is rejected. Other (non-mismatch) errors from verifyInstallation are rethrown unchanged.","triggerScenarios":"verifyOfflineLicenseToken(token) (via activateOfflineLicenseToken or getOfflineLicense) where the token's identifier.installId or identifier.tenantId differs from the current install's — the token was issued for a different install or tenant.","commonSituations":"Moving an offline license from one self-hosted server to another without re-issuing; re-provisioned servers where installation.getInstall() produced a new installId; multi-tenant misuse (token issued for tenant A used under tenant B); backups restored into a fresh install.","solutions":["On the target installation, export its identifier (getIdentifierBase64) and request a new offline token bound to it from the account portal.","If migrating servers, deactivate the license on the old install and issue a token for the new install's identifier.","After a restore that changed installId, contact Budibase support to reissue the license for the new install.","Confirm the activation runs under the same tenant the token was generated for."],"exampleFix":"// before\nawait activateOfflineLicenseToken(tokenIssuedForOldServer)\n// after\nconst identifierBase64 = await getIdentifierBase64()\n// use identifierBase64 when requesting the token in the account portal, then:\nawait activateOfflineLicenseToken(tokenIssuedForThisServer)","handlingStrategy":"validation","validationCode":"const identifierBase64 = await getIdentifierBase64()\n// Request the offline token from the portal using identifierBase64 so it is bound to this install\n// Then decode the returned token and confirm:\nconst decoded = /* decode token */ as OfflineLicense\nconst identifier = await getIdentifier()\nif (decoded.identifier.installId !== identifier.installId) {\n  throw new Error(\"Token bound to a different installId\")\n}","typeGuard":"function isMismatchError(e: unknown): boolean {\n  return e instanceof HTTPError && e.message === \"Offline license does not match this installation\"\n}","tryCatchPattern":"try {\n  await activateOfflineLicenseToken(token)\n} catch (e) {\n  if (isMismatchError(e)) {\n    // re-export this install's identifier and request a matching token\n  } else throw e\n}","preventionTips":["Always export the identifier from the exact install being activated.","One token per installation — never reuse across servers/tenants.","Reissue tokens whenever installId changes (fresh installs, some restores).","Record which installId each offline token was issued for."],"tags":["licensing","offline-license","install-mismatch","tenant"],"backgroundTag":"offline-license-mismatch","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}