{"record":{"id":"12c7406a7a95b3c0","repo":"Budibase/budibase","slug":"invalid-offline-license-token","errorCode":null,"errorMessage":"Invalid offline license token","messagePattern":"Invalid offline license token","errorType":"exception","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/pro/src/sdk/licensing/licenses/offline/offline.ts","lineNumber":109,"sourceCode":"  const hosting = Hosting.SELF // offline only applicable in self host\n  const _features = features.getOfflineFeatures(planType)\n  const _quotas = quotas.getQuotas(hosting, planType)\n\n  // apply the latest features and quotas to license\n  license.features = union(license.features, _features)\n  license.quotas = merge(license.quotas, _quotas)\n\n  return license\n}\n\nexport async function verifyOfflineLicenseToken(\n  token: string\n): 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","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/pro/src/sdk/licensing/licenses/offline/offline.ts#L91-L127","documentation":"verifyOfflineLicenseToken wraps signing.verifyLicenseToken and, if signature/decoding verification fails for any reason, throws HTTPError('Invalid offline license token', 400). It means the token string is not a validly signed offline license: bad signature, malformed payload, wrong encoding, or tampering.","triggerScenarios":"Calling verifyOfflineLicenseToken(token) (directly or via activateOfflineLicenseToken) with a token that fails cryptographic verification — truncated string, extra whitespace/newlines, altered payload, wrong signing key, or not a license token at all.","commonSituations":"Copy-paste errors when transferring the token file contents (missing characters, added quotes/whitespace); token from a different Budibase version with an incompatible format; attempting to use a JWT or other token type as an offline license; expired signing keys after an upgrade.","solutions":["Re-copy the token exactly as provided by the account portal — no added whitespace, quotes, or line breaks.","Download a fresh offline license token from the account portal for this installation's identifier.","Ensure the Budibase/pro version matches the era the token was issued for; upgrade if formats changed.","Verify you are passing the offline license token, not a license key or an API key."],"exampleFix":"// before\nawait activateOfflineLicenseKey(rawFileContents) // may include trailing newline/quotes\n// after\nconst token = rawFileContents.trim().replace(/^\"|\"$/g, \"\")\nawait activateOfflineLicenseToken(token)","handlingStrategy":"validation","validationCode":"function looksLikeLicenseToken(token: string): boolean {\n  const t = token.trim()\n  return t.length > 0 && !t.includes(\"\\n\") && t.split(\".\").length >= 2\n}\nif (!looksLikeLicenseToken(token)) throw new Error(\"Not a valid offline license token format\")","typeGuard":"function isNonEmptyString(v: unknown): v is string {\n  return typeof v === \"string\" && v.trim().length > 0\n}","tryCatchPattern":"try {\n  await activateOfflineLicenseToken(token)\n} catch (e) {\n  if (e instanceof HTTPError && e.status === 400 && e.message === \"Invalid offline license token\") {\n    // re-copy token from portal export; check for truncation/whitespace\n  } else throw e\n}","preventionTips":["Copy tokens via file transfer rather than manual copy-paste where possible.","Trim whitespace and surrounding quotes from token contents.","Confirm the file holds the offline license token, not a license key.","Keep Budibase versions aligned with the portal version that signed the token."],"tags":["licensing","offline-license","signature","validation"],"backgroundTag":"invalid-license-token","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}