{"record":{"id":"5695c6e4657649c7","repo":"n8n-io/n8n","slug":"this-invite-has-been-accepted-already","errorCode":null,"errorMessage":"This invite has been accepted already","messagePattern":"This invite has been accepted already","errorType":"exception","errorClass":"BadRequestError","httpStatus":400,"severity":"warning","filePath":"packages/cli/src/controllers/invitation.controller.ts","lineNumber":127,"sourceCode":"\t\tif (users.length !== 2) {\n\t\t\tthis.logger.debug(\n\t\t\t\t'Request to fill out a user shell failed because the inviter ID and/or invitee ID were not found in database',\n\t\t\t\t{\n\t\t\t\t\tinviterId,\n\t\t\t\t\tinviteeId,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthrow new BadRequestError('Invalid payload or URL');\n\t\t}\n\n\t\tconst invitee = users.find((user) => user.id === inviteeId) as User;\n\n\t\tif (invitee.password) {\n\t\t\tthis.logger.debug(\n\t\t\t\t'Request to fill out a user shell failed because the invite had already been accepted',\n\t\t\t\t{ inviteeId },\n\t\t\t);\n\t\t\tthrow new BadRequestError('This invite has been accepted already');\n\t\t}\n\n\t\tinvitee.firstName = firstName;\n\t\tinvitee.lastName = lastName;\n\t\tinvitee.password = await this.passwordUtility.hash(password);\n\n\t\tconst updatedUser = await this.userRepository.save(invitee, { transaction: false });\n\n\t\tthis.authService.issueCookie(res, updatedUser, false, req.browserId);\n\n\t\tthis.eventService.emit('user-signed-up', {\n\t\t\tuser: updatedUser,\n\t\t\tuserType: 'email',\n\t\t\twasDisabledLdapUser: false,\n\t\t});\n\n\t\tconst publicInvitee = await this.userService.toPublic(invitee);\n","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/controllers/invitation.controller.ts#L109-L145","documentation":"A BadRequestError (HTTP 400) from processInvitationAcceptance when the resolved invitee already has a password set. A non-null invitee.password means the shell user was already filled out, so the invite is single-use and cannot be accepted again. Logged at debug with the inviteeId before throwing.","triggerScenarios":"POST to the acceptance endpoint with a token whose invitee already completed setup (password is set). Re-clicking an already-used invite link, or a duplicate submission of the same form, triggers it.","commonSituations":"User clicks the invite link a second time after already setting up; browser retry/double-submit; shared invite link reused by a different person; the invitee forgot they completed setup and tries again.","solutions":["Tell the user the invite was already accepted and have them log in with the credentials they set.","If they forgot the password, use the password-reset flow instead of the invite link.","Guard the UI to disable the submit button after the first successful acceptance to prevent double-submit."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Client cannot know accept-state; rely on try/catch and redirect to login.","typeGuard":null,"tryCatchPattern":"try {\n  await api.post('/accept-invitation', { token, firstName, lastName, password });\n} catch (e) {\n  if (e.response?.status === 400 && /already been accepted/i.test(e.response.data.message)) {\n    redirect('/signin');\n    return;\n  }\n  throw e;\n}","preventionTips":["Disable the accept-invite submit button after the first success to prevent double-submit.","Tell users who forgot their password to use the reset flow, not the invite link.","Do not reuse invite links across multiple people."],"tags":["invitations","token","rest-api","duplicate"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}