{"record":{"id":"2aa27779f84d42c0","repo":"paperclipai/paperclip","slug":"invite-already-consumed","errorCode":null,"errorMessage":"Invite already consumed","messagePattern":"Invite already consumed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-host-services.ts","lineNumber":3011,"sourceCode":"          entityId: created.id,\n          details: {\n            allowedJoinTypes: created.allowedJoinTypes,\n            expiresAt: created.expiresAt.toISOString(),\n            hasAgentMessage: Boolean(normalizedAgentMessage),\n          },\n        });\n        return { ...redactInvite(created), token };\n      },\n      async revokeInvite(params) {\n        const companyId = ensureCompanyId(params.companyId);\n        await ensurePluginAvailableForCompany(companyId);\n        const invite = await db\n          .select()\n          .from(invites)\n          .where(and(eq(invites.id, params.inviteId), eq(invites.companyId, companyId)))\n          .then((rows) => rows[0] ?? null);\n        if (!invite) throw new Error(\"Invite not found\");\n        if (invite.acceptedAt) throw new Error(\"Invite already consumed\");\n        if (invite.revokedAt) return redactInvite(invite);\n        const revoked = await db\n          .update(invites)\n          .set({ revokedAt: new Date(), updatedAt: new Date() })\n          .where(eq(invites.id, invite.id))\n          .returning()\n          .then((rows) => rows[0] ?? invite);\n        await logPluginActivity({\n          companyId,\n          action: \"invite.revoked_by_plugin\",\n          entityType: \"invite\",\n          entityId: invite.id,\n        });\n        return redactInvite(revoked);\n      },\n    },\n\n    authorization: {","sourceCodeStart":2993,"sourceCodeEnd":3029,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/services/plugin-host-services.ts#L2993-L3029","documentation":"revokeInvite located the invite but its status shows it was already consumed by a joiner. Consumed invites cannot be revoked; the token has already been redeemed.","triggerScenarios":"Thrown at server/src/services/plugin-host-services.ts:3002 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The invite was already used. Issue a new invite instead of reusing the consumed token."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}