Invite rate limit charges failed invites against the daily budget
Issue Summary
Since #9182 the invite budget is charged before the invite is created, so recipients whose invite fails still use up the organization's daily budget. Before #9182 the single-invite path recorded usage only when an invite was actually created.
apps/web/modules/organization/settings/teams/actions.ts on main (e68a469a):
inviteUserActioncallsapplyInviteRateLimit(parsedInput.organizationId)at line 342, beforeinviteUser(...)at line 344.bulkInviteUsersActioncallsapplyInviteRateLimit(organizationId, invitees.length)at line 442 for the whole batch, before the per-recipient loop. Recipients that then fail —user_already_member,invite_already_exists,duplicate_team_ids,invalid_team_idsfromlib/invite-failure.ts— are only reported back assuccess: false(lines 467 and 470).- The onboarding invite action does the same (
apps/web/modules/setup/organization/[organizationId]/invite/actions.ts:36).
Before #9182 (313470bf, actions.ts:366):
if (inviteId) {
await recordRateLimitUsage(rateLimitConfigs.actions.inviteMember, parsedInput.organizationId);checkRateLimit now takes the units with an atomic INCRBY, and nothing in rate-limit.ts or helpers.ts gives them back.
Example on a self-hosted instance with the default INVITE_RATE_LIMIT_PER_24_HOURS=50: a bulk invite of 40 addresses where 15 people are already members creates 25 invites, charges 40, and leaves 10 for the rest of the day.
Expected Behavior
Only recipients that actually got an invite count against the budget, as before #9182 — for example by refunding the failed count after the bulk loop, or by recording usage per created invite while keeping the up-front check that refuses oversized requests.
Other information (incl. screenshots, Formbricks version, steps to reproduce,...)
The comment on the Lua script ("Refusing before INCRBY prevents an oversized request from consuming the remaining budget") is about oversized requests, not failed invites, and the PR description does not mention failures either, so I don't think charging them was intended. Close this if it is the anti-abuse trade-off you want.
Your Environment
Formbricks main at e68a469a (the merge of #9182). Read from source; I have not reproduced it on a running instance.
To be upfront about where this came from: I found it with a code review tool I am building (ReviewGate) while running it over real repositories, then compared the code before and after #9182 by hand before writing this up.
Source: formbricks/formbricks