Budibase/budibase · warning · UsageLimitWarning
${action.name}
Error message
${action.name} What it means
After computing the new total usage for an action, updateUsage compares it against the licensed quota value. If the quota is not UNLIMITED, the total would exceed the limit, and the usageChange is positive (increment), it throws a UsageLimitWarning whose message is simply the quota action name. Decrementing is deliberately allowed so a tenant can climb back down after exceeding a quota. The thrown name is the quota name, not a human sentence — callers are expected to wrap it.
Source
Thrown at packages/pro/src/sdk/quotas/quotas.ts:388
}
let triggers: QuotaTriggers = {}
if (!action.opts?.dryRun) {
triggers = await checkTriggers(
action.type,
action.name,
totalValue,
licensedQuota
)
triggersToApply = { ...triggersToApply, [action.name]: triggers }
}
if (
licensedQuota.value !== constants.UNLIMITED &&
totalValue > licensedQuota.value &&
action.usageChange > 0 // allow for decrementing usage when the quota is already exceeded
) {
throw new UsageLimitWarning(`${action.name}`)
}
// never go negative if the quota has previously been exceeded
totalValue = Math.max(0, totalValue)
if (appValue) {
appValue = Math.max(0, appValue)
}
if (breakdownValue != null) {
breakdownValue = Math.max(0, breakdownValue)
breakdownValuesToApply = {
...breakdownValuesToApply,
[action.name]: breakdownValue,
}
}
// Apply functions if it is not a dry run
if (!action.opts?.dryRun) {
// if a value function is providedView on GitHub (pinned to a81a902e9a)
Solutions
- Free up usage by deleting resources (or wait for monthly reset) before incrementing again
- Upgrade the plan/license to raise the specific quota named in the message
- Catch UsageLimitWarning and map the quota name to a user-friendly limit message
- Review bulk operations to pre-check quota headroom before large imports
Example fix
// before: name-only warning propagates raw
try { await createRows(rows) } catch (e) { throw e }
// after: translate the quota name
try {
await createRows(rows)
} catch (err) {
if (err instanceof UsageLimitWarning) {
throw new Error(`You have reached your ${err.message} quota limit — upgrade to continue`)
}
throw err
} Defensive patterns
Strategy: try-catch
Validate before calling
const current = await quotas.getUsage(action.name)
const limit = await quotas.getLicensedLimit(action.name)
if (limit !== constants.UNLIMITED && current + usageChange > limit) {
// block operation up-front and show upgrade prompt
} Try / catch
try {
await createResource()
} catch (err) {
if (err instanceof UsageLimitWarning) {
throw new Error(`Quota limit reached: ${err.message} — upgrade your plan`)
}
throw err
} Prevention
- Check quota headroom before bulk imports or automations
- Map thrown quota names to friendly UI messages
- Reconcile usage after plan downgrades to restore headroom
When it happens
Trigger: An increment (e.g. creating rows/users/queries/apps) that would push monthly or static usage past the licensed quota value while usage is already at or above the limit.
Common situations: Free-plan tenant hitting row or user caps; automation bulk-creating records that overshoot a quota mid-run; license downgrade shrinking a quota below current usage so every subsequent increment throws; apps/users import exceeding static quotas.
Related errors
- USAGE_LIMIT_EXCEEDED
- App context required for quota update
- License not found for tenant id ${tenantId}
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/74f1c166b108409e.
Report an issue: GitHub.