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

  1. Reduce the 'adding' value in the request body until the preview succeeds.
  2. Split the seat increase into multiple smaller changes if business rules allow.
  3. Raise the subtotal/seat limit for this subscription via plan upgrade or admin configuration.
  4. 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

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


AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03). Data as JSON: /api/errors/e7f0bad9e5ef774c. Report an issue: GitHub.