{"record":{"id":"e7f0bad9e5ef774c","repo":"overleaf/overleaf","slug":"subtotal-limit-exceeded","errorCode":"subtotal_limit_exceeded","errorMessage":"subtotal_limit_exceeded","messagePattern":"subtotal_limit_exceeded","errorType":"http","errorClass":"SubtotalLimitExceededError","httpStatus":422,"severity":"warning","filePath":"services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs","lineNumber":236,"sourceCode":"    const preview =\n      await SubscriptionGroupHandler.promises.previewAddSeatsSubscriptionChange(\n        userId,\n        body.adding\n      )\n\n    res.json(preview)\n  } catch (error) {\n    if (\n      error instanceof MissingBillingInfoError ||\n      error instanceof InactiveError ||\n      error instanceof HasPastDueInvoiceError ||\n      error instanceof HasNoAdditionalLicenseWhenManuallyCollectedError\n    ) {\n      return res.status(422).end()\n    }\n\n    if (error instanceof SubtotalLimitExceededError) {\n      return res.status(422).json({\n        code: 'subtotal_limit_exceeded',\n        adding: body.adding,\n      })\n    }\n\n    logger.err(\n      { error },\n      'error trying to preview \"add seats\" subscription change'\n    )\n\n    return res.status(500).end()\n  }\n}\n\n/**\n * @param {import(\"express\").Request} req\n * @param {import(\"express\").Response} res\n * @returns {Promise<void>}","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/overleaf/overleaf/blob/28ad3b03b71cb4311decdcb55c36b33ec10d72db/services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs#L218-L254","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst res = await fetch(url, {method:'POST', body: JSON.stringify({adding: 500})})\n// after: respect the limit reported by the server\nif (res.status === 422) {\n  const {code, adding} = await res.json()\n  if (code === 'subtotal_limit_exceeded') {\n    showError(`Cannot add ${adding} seats: subtotal limit exceeded. Add fewer seats or upgrade the plan.`)\n    return\n  }\n}","handlingStrategy":"validation","validationCode":"// validate the seat count against the configured subtotal limit before calling preview\nfunction withinSubtotalLimit(currentSubtotal, adding, limit) {\n  return adding >= 1 && (currentSubtotal + adding * SEAT_PRICE) <= limit\n}","typeGuard":null,"tryCatchPattern":"try {\n  const preview = await SubscriptionGroupHandler.promises.previewAddSeatsSubscriptionChange(userId, adding)\n} catch (err) {\n  if (err instanceof SubtotalLimitExceededError)\n    return res.status(422).json({code: 'subtotal_limit_exceeded', adding})\n  throw err\n}","preventionTips":["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"],"tags":["http-422","subscription","seat-limit","billing"],"backgroundTag":"subtotal-limit-exceeded","analyzedSha":"28ad3b03b71cb4311decdcb55c36b33ec10d72db","analyzedAt":"2026-09-03T02:10:22.807Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}