Budibase/budibase · critical · HTTPError

Error getting license: ${message}

Error message

Error getting license: ${message}

What it means

When the licensing client fetches a tenant license from the licensing service, any non-200 response is converted into an HTTPError whose message embeds the upstream error text retrieved by getResponseErrorMessage, plus the upstream status code. A 404 (or a missing license response that isn't handled earlier) means the tenant has no license; 401/403 mean auth problems; 5xx mean the licensing service failed.

Source

Thrown at packages/pro/src/sdk/licensing/licenses/client.ts:133

            tenantId: installTenantId,
            version: installVersion,
          },
        }

        try {
          const response = await api.post(`/api/license`, {
            headers: { ...authHeader },
            body,
          })

          if (response.status === 404 || response.status === 403) {
            // no license for the tenant
            return
          }

          if (response.status !== 200) {
            const message = await getResponseErrorMessage(response)
            throw new HTTPError(
              `Error getting license: ${message}`,
              response.status
            )
          }

          return response.json()
        } catch (err) {
          // account portal isn't present - no license found
          if (env.DISABLE_ACCOUNT_PORTAL) {
            return
          }
          throw err
        }
      }
    )
  })
}

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Check the embedded status code: if 404, confirm the tenant actually has a license and the license key is correctly configured.
  2. If 401/403, fix the license key / API credentials used to authenticate with the licensing service.
  3. If 5xx or network errors, retry with backoff and check the licensing service status; wrap the call in retry logic.
  4. Refresh the cached license after fixing credentials so subsequent feature checks succeed.

Example fix

// before
const license = await licenses.getCachedLicense() // throws HTTPError
// after
let license
try {
  license = await licenses.getCachedLicense()
} catch (err) {
  if (err instanceof HTTPError && err.status === 404) {
    license = null // no license for tenant — handle gracefully
  } else {
    throw err
  }
}
Defensive patterns

Strategy: retry

Validate before calling

const hasKey = !!env.SELF_HOSTED_LICENSE_KEY || !!licenseConfig
if (!hasKey) { /* skip license fetch; run in unlicensed mode */ }

Type guard

function isLicenseHttpError(err: unknown): err is HTTPError {
  return err instanceof HTTPError && typeof err.status === "number"
}

Try / catch

try {
  license = await getLicense()
} catch (err) {
  if (err instanceof HTTPError) {
    if (err.status === 404) { /* no license — degrade */ }
    else if (err.status >= 500 || err.status === 429) { /* retry with backoff */ }
    else { /* fix credentials/license key */ }
  } else throw err
}

Prevention

When it happens

Trigger: Calling _getLicense (via the client's get license path) when the licensing API responds with a non-200 status: unlicensed tenant (404), invalid/expired license key or credentials (401/403), or a licensing service outage (5xx).

Common situations: Self-hosted Budibase where SELF_HOSTED_LICENSE_KEY is unset or invalid; the licensing account service is unreachable/degraded; tenant id mismatch so the license lookup 404s; network/proxy issues causing gateway errors.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/462d4e913e755db5. Report an issue: GitHub.