{"record":{"id":"7c3bc5679d41cc13","repo":"koala73/worldmonitor","slug":"cannot-invite-self","errorCode":"CANNOT_INVITE_SELF","errorMessage":"CANNOT_INVITE_SELF","messagePattern":"CANNOT_INVITE_SELF","errorType":"error_code","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/payments/businessSeats.ts","lineNumber":182,"sourceCode":"        q.eq(\"businessSubscriptionId\", businessSub.dodoSubscriptionId),\n      )\n      .collect();\n    const existingByEmail = new Map(\n      existingGrants.map((g) => [g.inviteeEmail, g]),\n    );\n\n    // Separate new invites from duplicates before the cap check so a duplicate\n    // re-invite is idempotent even when the cap is full.\n    const newEmails: string[] = [];\n    const results: Array<{\n      email: string;\n      grantId: string;\n      status: \"created\" | \"already_pending\" | \"already_accepted\";\n    }> = [];\n\n    for (const email of emails) {\n      if (email === normalizedOwnerEmail) {\n        throw new ConvexError({ kind: \"CANNOT_INVITE_SELF\" });\n      }\n      if (!isCorporateDomain(email)) {\n        throw new ConvexError({ kind: \"INVITEE_DOMAIN_NOT_CORPORATE\" });\n      }\n      if (!sameDomain(ownerEmail, email)) {\n        throw new ConvexError({ kind: \"INVITEE_DOMAIN_MISMATCH\" });\n      }\n\n      const existing = existingByEmail.get(email);\n      if (existing) {\n        if (existing.status === \"accepted\") {\n          results.push({ email, grantId: existing._id, status: \"already_accepted\" });\n          continue;\n        }\n        if (existing.status === \"pending\" && existing.expiresAt > now) {\n          results.push({ email, grantId: existing._id, status: \"already_pending\" });\n          continue;\n        }","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/koala73/worldmonitor/blob/ffec79ac339946fd2d24e85845da5755dcaa534b/convex/payments/businessSeats.ts#L164-L200","documentation":"Thrown by `inviteSeats` during the per-email loop when an invitee address equals the owner's own (normalized) email. Owners cannot invite themselves as a seat. Object-typed ConvexError (`{ kind: \"CANNOT_INVITE_SELF\" }`).","triggerScenarios":"The owner's email appears in the `emails` array passed to `inviteSeats` (e.g. `inviteSeats({ emails: [\"owner@acme.com\"] })` where owner@acme.com is the caller).","commonSituations":"Owner pasted their own address by mistake; an autocomplete defaulted to the signed-in user; 'invite all' from a contact list that included the owner.","solutions":["Remove the owner's own email from the invite list before submitting.","Client-side, filter out the current user's email from the recipients.","Warn if the owner's address is detected in the input."],"exampleFix":"// before\nawait inviteSeats({ emails: [\"owner@acme.com\", \"a@acme.com\"] });\n\n// after\nconst emails = recipients.filter(e => e !== currentUserEmail);\nawait inviteSeats({ emails });","handlingStrategy":"validation","validationCode":"const emails = rawEmails.filter(e => e.trim().toLowerCase() !== ownerEmail.toLowerCase());\nif (emails.length === 0) { showToast(\"You can't invite yourself.\"); return; }\nawait inviteSeats({ emails });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Strip the current user's email from the recipient list client-side.","Warn when the owner's address appears in the input."],"tags":["validation","convex","business-seats","billing"],"backgroundTag":null,"analyzedSha":"ffec79ac339946fd2d24e85845da5755dcaa534b","analyzedAt":"2026-08-12T11:24:56.012Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}