koala73/worldmonitor · error · ConvexError

CANNOT_INVITE_SELF

CANNOT_INVITE_SELF

Error message

CANNOT_INVITE_SELF

What it means

Structured ConvexError thrown by inviteSeats when one of the submitted emails equals the owner's own normalized email. Owners already hold the Business entitlement; inviting yourself is rejected while iterating the invitee list.

Solutions

  1. Remove the owner's own address from the invite list
  2. Filter the signed-in user's email out of the batch in the invite UI
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at convex/payments/businessSeats.ts:182 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/7c3bc5679d41cc13. Report an issue: GitHub.

Appendix: source

Thrown at convex/payments/businessSeats.ts:181

        q.eq("businessSubscriptionId", businessSub.dodoSubscriptionId),
      )
      .collect();
    const existingByEmail = new Map(
      existingGrants.map((g) => [g.inviteeEmail, g]),
    );

    // Separate new invites from duplicates before the cap check so a duplicate
    // re-invite is idempotent even when the cap is full.
    const newEmails: string[] = [];
    const results: Array<{
      email: string;
      grantId: string;
      status: "created" | "already_pending" | "already_accepted";
    }> = [];

    for (const email of emails) {
      if (email === normalizedOwnerEmail) {
        throw new ConvexError({ kind: "CANNOT_INVITE_SELF" });
      }
      if (!isCorporateDomain(email)) {
        throw new ConvexError({ kind: "INVITEE_DOMAIN_NOT_CORPORATE" });
      }

      const existing = existingByEmail.get(email);
      if (existing) {
        if (existing.status === "accepted") {
          results.push({ email, grantId: existing._id, status: "already_accepted" });
          continue;
        }
        if (existing.status === "pending" && existing.expiresAt > now) {
          results.push({ email, grantId: existing._id, status: "already_pending" });
          continue;
        }
      }
      newEmails.push(email);
    }

View on GitHub (pinned to 7d06c8633d)