{"record":{"id":"b5ff84875955c1dc","repo":"n8n-io/n8n","slug":"user-to-generate-invite-link-for-not-found","errorCode":null,"errorMessage":"User to generate invite link for not found","messagePattern":"User to generate invite link for not found","errorType":"exception","errorClass":"NotFoundError","httpStatus":404,"severity":"error","filePath":"packages/cli/src/controllers/users.controller.ts","lineNumber":182,"sourceCode":"\t\t\tuser.role.slug === GLOBAL_OWNER_ROLE.slug\n\t\t) {\n\t\t\tthrow new ForbiddenError('Admin cannot reset password of global owner');\n\t\t}\n\n\t\tconst link = this.authService.generatePasswordResetUrl(user);\n\t\treturn { link };\n\t}\n\n\t@Post('/:id/invite-link')\n\t@GlobalScope('user:generateInviteLink')\n\tasync generateInviteLink(req: AuthenticatedRequest<{ id: string }, {}, {}, {}>, _res: Response) {\n\t\tconst inviterId = req.user.id;\n\t\tconst inviteeId = req.params.id;\n\n\t\tconst targetUser = await this.userRepository.findOne({ where: { id: inviteeId } });\n\n\t\tif (!targetUser) {\n\t\t\tthrow new NotFoundError('User to generate invite link for not found');\n\t\t}\n\n\t\tconst token = this.jwtService.sign(\n\t\t\t{\n\t\t\t\tinviterId,\n\t\t\t\tinviteeId,\n\t\t\t},\n\t\t\t{\n\t\t\t\texpiresIn: '90d',\n\t\t\t},\n\t\t);\n\n\t\tconst baseUrl = this.urlService.getInstanceBaseUrl();\n\t\tconst inviteLink = `${baseUrl}/signup?token=${token}`;\n\n\t\treturn { link: inviteLink };\n\t}\n","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/controllers/users.controller.ts#L164-L200","documentation":"Thrown by POST /users/:id/invite-link (scope user:generateInviteLink) when userRepository.findOne({where:{id:inviteeId}}) returns null — i.e. no user exists for the path id. Unlike findOneOrFail, this is a plain findOne so the explicit null check is the only guard; HTTP 404.","triggerScenarios":"POST /users/<unknown-id>/invite-link where <unknown-id> is not present in the users table (typo, deleted invitee, invitee id from a different environment).","commonSituations":"Re-triggering an invite-link generation for an invitee whose row was purged by the cleanup job; cross-environment id copy; UI caching a stale user list.","solutions":["Verify the invitee id via GET /users/:id before requesting an invite link.","If the invitee was deleted, recreate the user/invite rather than regenerating the link.","Do not retry the same id; treat 404 as terminal."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"async function ensureInviteeExists(id: string) {\n  const r = await fetch(`/rest/users/${id}`);\n  if (r.status === 404) throw new Error(`Invitee ${id} not found; recreate the invite instead`);\n}\n// call before POST /users/:id/invite-link","typeGuard":null,"tryCatchPattern":"try { await fetch(`/rest/users/${id}/invite-link`, { method: 'POST' }); }\ncatch (e) { if (e.statusCode === 404) { /* recreate invite */ } else throw e; }","preventionTips":["Refresh the user/invitee list before regenerating links.","Do not assume an id from a previous environment exists in this one.","Link regeneration is for existing rows; recreate deleted invites."],"tags":["users","invite","rest-api","not-found"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}