overleaf/overleaf · warning · SubtotalLimitExceededError
subtotal_limit_exceeded
subtotal_limit_exceeded
Error message
subtotal_limit_exceeded
What it means
An HTTP 422 JSON response with code 'subtotal_limit_exceeded' returned by previewAddSeatsSubscriptionChange when adding the requested seats would push the subscription's subtotal past the allowed limit (SubtotalLimitExceededError thrown by the handler). The response echoes the requested seat count so the client can inform the user.
Source
Thrown at services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs:236
const preview =
await SubscriptionGroupHandler.promises.previewAddSeatsSubscriptionChange(
userId,
body.adding
)
res.json(preview)
} catch (error) {
if (
error instanceof MissingBillingInfoError ||
error instanceof InactiveError ||
error instanceof HasPastDueInvoiceError ||
error instanceof HasNoAdditionalLicenseWhenManuallyCollectedError
) {
return res.status(422).end()
}
if (error instanceof SubtotalLimitExceededError) {
return res.status(422).json({
code: 'subtotal_limit_exceeded',
adding: body.adding,
})
}
logger.err(
{ error },
'error trying to preview "add seats" subscription change'
)
return res.status(500).end()
}
}
/**
* @param {import("express").Request} req
* @param {import("express").Response} res
* @returns {Promise<void>}View on GitHub (pinned to 28ad3b03b7)
Solutions
- Reduce the 'adding' value in the request body until the preview succeeds.
- Split the seat increase into multiple smaller changes if business rules allow.
- Raise the subtotal/seat limit for this subscription via plan upgrade or admin configuration.
- Use the 'adding' value in the 422 response body to show the user exactly which request was rejected.
Example fix
// before
const res = await fetch(url, {method:'POST', body: JSON.stringify({adding: 500})})
// after: respect the limit reported by the server
if (res.status === 422) {
const {code, adding} = await res.json()
if (code === 'subtotal_limit_exceeded') {
showError(`Cannot add ${adding} seats: subtotal limit exceeded. Add fewer seats or upgrade the plan.`)
return
}
} Defensive patterns
Strategy: validation
Validate before calling
// validate the seat count against the configured subtotal limit before calling preview
function withinSubtotalLimit(currentSubtotal, adding, limit) {
return adding >= 1 && (currentSubtotal + adding * SEAT_PRICE) <= limit
} Try / catch
try {
const preview = await SubscriptionGroupHandler.promises.previewAddSeatsSubscriptionChange(userId, adding)
} catch (err) {
if (err instanceof SubtotalLimitExceededError)
return res.status(422).json({code: 'subtotal_limit_exceeded', adding})
throw err
} Prevention
- Always call the preview endpoint before create to detect the limit early
- Clamp body.adding to a sane maximum client-side
- Show remaining seat/subtotal headroom in the admin UI
- Watch for the code field 'subtotal_limit_exceeded' in 422 responses rather than the empty-body 422
When it happens
Trigger: POST to the add-seats preview endpoint with body.adding = N where the current subscription subtotal + N seats exceeds the configured maximum subtotal. The handler throws SubtotalLimitExceededError during the preview calculation.
Common situations: Admins attempting very large seat additions (e.g. adding hundreds of users at once); subscriptions already near their plan/credit limit; misconfigured per-subscription subtotal caps in the environment.
Related errors
- This subscription is being collected manually
- This subscription has a past due invoice
- This subscription is being collected manually has no "additi
- doc updater could not load requested ops
- InvalidInstitutionalEmailError
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/e7f0bad9e5ef774c.
Report an issue: GitHub.