koala73/worldmonitor · error · ConvexError
INVITE_ALREADY_USED
INVITE_ALREADY_USED
Error message
INVITE_ALREADY_USED
What it means
Structured ConvexError thrown by acceptBusinessInvite when the referenced grant's status is not pending — i.e. the single-use invite was already accepted or revoked. Redeeming a used invite token is rejected by design.
Solutions
- If already accepted, no action is needed — entitlement is already granted
- Otherwise request a fresh invite from the Business owner
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at convex/payments/businessSeats.ts:468 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21).
Data as JSON: /api/errors/6b038c9b14950612.
Report an issue: GitHub.
Appendix: source
Thrown at convex/payments/businessSeats.ts:464
* grant to `accepted`, stamps `inviteeUserId`, and recomputes the invitee's
* entitlement. Single-use: accepted/revoked/expired tokens are rejected.
*/
export const acceptBusinessInvite = mutation({
args: { grantId: v.id("businessProGrants"), token: v.string() },
handler: async (ctx, args) => {
const userId = await requireUserId(ctx);
const identity = await resolveUserIdentity(ctx);
const inviteeEmail = identity?.email?.trim().toLowerCase();
if (!inviteeEmail) {
throw new ConvexError({ kind: "INVITEE_EMAIL_UNAVAILABLE" });
}
const grant = await ctx.db.get(args.grantId);
if (!grant) {
throw new ConvexError({ kind: "GRANT_NOT_FOUND" });
}
if (grant.status !== "pending") {
throw new ConvexError({ kind: "INVITE_ALREADY_USED" });
}
const now = Date.now();
if (grant.expiresAt <= now) {
throw new ConvexError({ kind: "INVITE_EXPIRED" });
}
if (!(await verifyBusinessInviteToken(args.grantId, args.token))) {
throw new ConvexError({ kind: "INVALID_INVITE_TOKEN" });
}
if (grant.inviteeEmail !== inviteeEmail) {
throw new ConvexError({ kind: "INVITE_EMAIL_MISMATCH" });
}
if (!sameDomain(grant.inviteeEmail, inviteeEmail)) {
throw new ConvexError({ kind: "INVITE_EMAIL_MISMATCH" });
}
if (!isCorporateDomain(inviteeEmail)) {
throw new ConvexError({ kind: "INVITEE_DOMAIN_NOT_CORPORATE" });
}
View on GitHub (pinned to 7d06c8633d)