Budibase/budibase · error
App context required for quota update
Error message
App context required for quota update
What it means
Some quota names in APP_QUOTA_NAMES are tracked per-app and therefore require an appId to attribute usage. In updateUsage, when such an action is processed without an appId in the context, the function throws this error rather than recording usage against an unknown app. It is an internal invariant guard on the quota update payload.
Source
Thrown at packages/pro/src/sdk/quotas/quotas.ts:342
let breakdownValuesToApply: any = {}
let triggersToApply: any = {}
for (let action of actions) {
await tracer.trace("quotas.updateUsage.action", async span => {
span.addTags({
actionName: action.name,
actionType: action.type,
actionUsageChange: action.usageChange,
})
try {
appId = context.getWorkspaceId()
} catch (err) {
// ignore error for now
}
// need an app ID for these
const isAppQuota = APP_QUOTA_NAMES.includes(action.name)
if (isAppQuota && !appId) {
throw new Error("App context required for quota update")
}
try {
licensedQuota = await getLicensedQuota(
QuotaType.USAGE,
action.name,
action.type
)
licenseQuotas.push(licensedQuota)
let {
total: totalValue,
app: appValue,
breakdown: breakdownValue,
} = await db.quotas.getCurrentUsageValues(
action.type,
action.name,
action.opts?.idView on GitHub (pinned to a81a902e9a)
Solutions
- Pass the current appId in the options when calling updateUsage/tryIncrement for app-scoped quotas
- Confirm the action name really is app-scoped — if it is tenant-level, it should not be in APP_QUOTA_NAMES
- Resolve appId from the request/automation context before recording usage
- If hit from a global context, split the logic so app quotas are only updated within an app context
Example fix
// before: incrementing an app-scoped quota without app context
await quotas.tryIncrement({ name: MonthlyQuotaName.QUERIES, usageChange: 1 })
// after
await quotas.tryIncrement({
name: MonthlyQuotaName.QUERIES,
usageChange: 1,
appId: ctx.appId,
}) Defensive patterns
Strategy: validation
Validate before calling
if (APP_QUOTA_NAMES.includes(action.name) && !appId) {
throw new Error(`${action.name} requires appId`)
} Type guard
function hasAppContext(opts: { name: string; appId?: string }): boolean {
return !APP_QUOTA_NAMES.includes(opts.name) || Boolean(opts.appId)
} Try / catch
try {
await updateUsage(action)
} catch (err: any) {
if (err.message === "App context required for quota update") {
// resolve appId from request/automation context and retry
} else { throw err }
} Prevention
- Always thread appId into quota updates from app-scoped code paths
- Audit tenant-level jobs for app-scoped quota increments
- Keep APP_QUOTA_NAMES and call sites in sync when adding quotas
When it happens
Trigger: Calling updateUsage/tryIncrement/decrement/usageLimitIsExceeded with an action whose name is an app-scoped quota (e.g. per-app queries, rows) while the options omit appId; an app-context-less code path (e.g. tenant-level cron or global API) touching an app quota.
Common situations: Calling quota SDK functions from workspace-agnostic code (worker jobs, global API handlers) that never resolve appId; refactoring that dropped appId from the options object; automations running outside an app execution context incrementing app-scoped quotas.
Related errors
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/a589a8df61482934.
Report an issue: GitHub.