Budibase/budibase · critical

License not found for tenant id ${tenantId}

Error message

License not found for tenant id ${tenantId}

What it means

getLicensedQuota resolves quota values from the tenant's license, which is obtained through the licensing cache. If no license is present in the cache for the tenant (getTenantId()), it cannot resolve any quota and throws with the tenant id embedded for diagnostics. Quota checks are meaningless without a license, so the function fails fast.

Source

Thrown at packages/pro/src/sdk/quotas/quotas.ts:463

        opts: { ...action.opts, tenantId },
      }))

    if (usageQuotas.length > 0) {
      await db.quotas.setAllUsage(usageQuotas)
    }
  })
}

export const getLicensedQuota = async (
  quotaType: QuotaType,
  name: MonthlyQuotaName | StaticQuotaName | ConstantQuotaName,
  usageType?: QuotaUsageType
): Promise<Quota> => {
  const license = await licensing.cache.getCachedLicense()

  if (!license) {
    const tenantId = tenancy.getTenantId()
    throw new Error("License not found for tenant id " + tenantId)
  }

  if (usageType && isStaticQuota(quotaType, usageType, name)) {
    return license.quotas[quotaType as QuotaType.USAGE][
      usageType as QuotaUsageType.STATIC
    ][name]
  } else if (usageType && isMonthlyQuota(quotaType, usageType, name)) {
    return license.quotas[quotaType as QuotaType.USAGE][
      usageType as QuotaUsageType.MONTHLY
    ][name]
  } else if (isConstantQuota(quotaType, name)) {
    return license.quotas[quotaType as QuotaType.CONSTANT][name]
  } else {
    throw new Error("Invalid quota type")
  }
}

export const usageLimitIsExceeded = async ({

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Activate/re-upload a valid license for the tenant so getCachedLicense() can hydrate
  2. Verify connectivity to the licensing service and force a license cache refresh, then retry
  3. Confirm the tenantId is correct (log/compare with the id in the error message)
  4. Check Redis/licensing cache health; restart the cache rehydration if the license exists but isn't cached

Example fix

// before: quota updates before the license is activated
await quotas.tryIncrement({ name: MonthlyQuotaName.ROWS, usageChange: 1 })
// after: ensure a license exists first
const license = await licensing.cache.getCachedLicense()
if (!license) {
  await activateLicense(licenseKey)
}
await quotas.tryIncrement({ name: MonthlyQuotaName.ROWS, usageChange: 1 })
Defensive patterns

Strategy: validation

Validate before calling

const license = await licensing.cache.getCachedLicense()
if (!license) throw new Error(`Activate a license for tenant ${tenancy.getTenantId()} before quota operations`)

Type guard

function isLicenseMissing(err: unknown): boolean {
  return err instanceof Error && err.message.startsWith("License not found for tenant id")
}

Try / catch

try {
  await updateUsage(action)
} catch (err) {
  if (isLicenseMissing(err)) {
    // trigger license activation / cache rehydration, then retry once
  } else { throw err }
}

Prevention

When it happens

Trigger: updateUsage or any quota resolution runs for a tenantId whose license is not in the licensing cache — license never activated, license fetch from licensing service failed, or the cache was cleared/expired and rehydration failed.

Common situations: Self-hosted install without an active license key attempting quota-gated operations; licensing service outage or network failure preventing license hydration into cache; tenant id mismatch (requesting quotas under a tenant that has no license record); Redis cache flush without license re-fetch.

Related errors


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