Budibase/budibase · error · HTTPError
Offline license does not match this installation
Error message
Offline license does not match this installation
What it means
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.
Source
Thrown at packages/pro/src/sdk/licensing/licenses/offline/offline.ts:122
): Promise<OfflineLicense> {
let license: OfflineLicense
try {
license = await signing.verifyLicenseToken(token)
} catch {
throw new HTTPError("Invalid offline license token", 400)
}
try {
verifyExpiry(license)
} catch {
throw new HTTPError("Offline license has expired", 400)
}
try {
await verifyInstallation(license)
} catch (e) {
if (e instanceof OfflineLicenseMismatchError) {
throw new HTTPError(
"Offline license does not match this installation",
400
)
}
throw e
}
return license
}
export async function getOfflineLicense(): Promise<License | undefined> {
try {
const token = await getOfflineLicenseToken()
if (token) {
const license = await verifyOfflineLicenseToken(token)
return enrichLicense(license)
}
} catch (e) {View on GitHub (pinned to a81a902e9a)
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.
Example fix
// before await activateOfflineLicenseToken(tokenIssuedForOldServer) // after const identifierBase64 = await getIdentifierBase64() // use identifierBase64 when requesting the token in the account portal, then: await activateOfflineLicenseToken(tokenIssuedForThisServer)
Defensive patterns
Strategy: validation
Validate before calling
const identifierBase64 = await getIdentifierBase64()
// Request the offline token from the portal using identifierBase64 so it is bound to this install
// Then decode the returned token and confirm:
const decoded = /* decode token */ as OfflineLicense
const identifier = await getIdentifier()
if (decoded.identifier.installId !== identifier.installId) {
throw new Error("Token bound to a different installId")
} Type guard
function isMismatchError(e: unknown): boolean {
return e instanceof HTTPError && e.message === "Offline license does not match this installation"
} Try / catch
try {
await activateOfflineLicenseToken(token)
} catch (e) {
if (isMismatchError(e)) {
// re-export this install's identifier and request a matching token
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid offline license
- Features do not exist for planType=${planType}
- Offline license has expired. expireAt=${license.expireAt}
- Invalid offline license token
- Offline license has expired
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/08489fcc5e7a0c3d.
Report an issue: GitHub.