Relationships
#1811 Invite failures emit no telemetry, so a rejected invitation leaves no trace anywhere
Opened by keeb · 8/24/2026
Found by code scan of the collective invite route.
The defect
routes/api/v1/collectives/[slug]/invite.ts:114 tracks the happy path only — a single track("collective_invite_sent", ...) call, passing the session user id and the slug.
That call sits after the success branch. Every rejection returns a JSON error and vanishes:
Unauthorized(401, line 40)Invalid request body(400, line 47)Username or email is required(400, line 54)Operative not found(400, line 69)Not found(404, line 87) when the slug does not resolve- anything thrown out of
inviteMember(400, line 103) — which covers thecanInviterejection, the already-a-member guard, and every Better AuthcreateInvitationthrow
None of these are counted, sampled, or logged as an event. The only durable artifact of a failed invite is the absence of a row in the invitation collection, which is indistinguishable from an invite that was never attempted.
Why this matters more than a usual missing metric
Inviting a collaborator is the first collaborative act in the product and the trigger for the trial. When it fails, the operative sees a red string in a form and nothing else happens — no email, no row, no event. From the outside there is no way to answer "did anyone try to invite someone today and get turned away," let alone "what did the server tell them." Diagnosing a single reported failure means reconstructing it from session-row write timestamps, because that is the only side effect a partially-completed invite leaves behind.
The taxonomy is small and already enumerated in the code, so the event is cheap.
Suggested fix
Emit collective_invite_failed on every non-2xx return from this route, carrying:
reason— a stable slug per branch (unauthorized,invalid-body,missing-identifier,operative-not-found,collective-not-found,role-not-allowed,already-member,provider-error)slug,inviter_username, and whether the submitted identifier was an email or a username (not the identifier itself)
Two things fall out of that immediately: which rejection dominates, and whether the operative-not-found rate tracks the typeahead gap in #1809.
Open
No activity in this phase yet.
Sign in to post a ripple.