n8n-io/n8n · error
Bad Gateway
Error message
Bad Gateway
What it means
CATALOG ANOMALY: the literal 'Bad Gateway' does not appear anywhere in project.controller.ts (it actually lives in telemetry.controller.ts:45). At the attributed line 323 the real code is the addProjectUsers response path: `if (conflicts.length > 0) return res.status(409).json({ conflicts });`, and the surrounding catch (lines 325-329) only converts UnlicensedProjectRoleError into a 400 and rethrows everything else as a generic 500. So the meaningful error surface here is either a structured 409 conflicts response or an unhandled 500 from an unexpected backend error during bulk user-add.
Source
Thrown at packages/cli/src/controllers/project.controller.ts:323
project: { id: project.id, name: project.name },
});
}
const relations = await this.projectsService.getProjectRelations(projectId);
this.eventService.emit('team-project-updated', {
userId: req.user.id,
role: req.user.role.slug,
members: relations.map((r) => ({ userId: r.userId, role: r.role.slug })),
projectId,
});
// Response semantics:
// - If at least one user was added, return 201. When there are also conflicts, include them in the body.
// - If no users were added but conflicts exist, return 409 with conflicts.
if (added.length > 0) {
return conflicts.length > 0 ? res.status(201).json({ conflicts }) : res.status(201).send();
}
if (conflicts.length > 0) return res.status(409).json({ conflicts });
return res.status(200).send();
} catch (e) {
if (e instanceof UnlicensedProjectRoleError) {
throw new BadRequestError(e.message);
}
throw e;
}
}
@Patch('/:projectId/users/:userId')
@ProjectScope('project:update')
async changeProjectUserRole(
req: AuthenticatedRequest,
res: Response,
@Param('projectId') projectId: string,
@Param('userId') userId: string,
@Body body: ChangeUserRoleInProject,
) {View on GitHub (pinned to 5ac6606e81)
Solutions
- Inspect the response status and body: 201 with {conflicts}, 409 with {conflicts}, or 500 (rethrown).
- For 409, resolve each conflict (e.g. user already a member, role mismatch) and retry the remaining users.
- For 500, check server logs for the rethrown root cause — do not retry unchanged.
Defensive patterns
Strategy: try-catch
Validate before calling
// Differentiate the documented response shapes before treating as error.
function classifyAddUsersResponse(res) {
if (res.status === 201 || res.status === 200) return 'ok';
if (res.status === 409) return 'conflicts'; // res.body.conflicts[]
return 'error';
} Type guard
function hasConflicts(body) {
return body && Array.isArray(body.conflicts);
} Try / catch
try {
const res = await api.post(`/projects/${projectId}/users`, payload);
if (res.status === 409 && res.data?.conflicts) {
// resolve per-user conflicts, retry the subset that can be added
}
} catch (e) {
if (e.status === 500) {
// inspect server logs; do not retry identical payload
} else if (e.status === 400 && /not licensed to use role/.test(e.message)) {
// switch to a licensed role
} else { throw e; }
} Prevention
- Always inspect status + conflicts body, not just success/failure.
- Note: the catalog 'Bad Gateway' label is mis-attributed here; treat responses by real status code.
When it happens
Trigger: POST /:projectId/users where some users cannot be added (returns 409 with a conflicts body), or where an unexpected non-UnlicensedProjectRole error escapes the catch and surfaces as 500 (DB constraint, missing role, FK violation).
Common situations: Adding users who are already members, or whose target role is invalid, producing conflicts; a transient DB/backend failure during the bulk add; the body must be inspected to distinguish 'partial success with conflicts' from a hard failure.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- Your instance is not licensed to use role "${role}".
- Down migration only possible when there are no projects. Ple
- Could not determine personal project ID
- Project not found
- Could not find the folder: ${folderId}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/968b34a46d88e84c.
Report an issue: GitHub.