n8n-io/n8n · error · BadRequestError

Request to delete a user failed because the user to delete a

Error message

Request to delete a user failed because the user to delete and the transferee are the same user

What it means

Thrown by DELETE /users/:id when the transferId query parameter equals the personal-project id of the user being deleted — i.e. the workflows/credentials would be transferred back to the same (personal) project being removed. HTTP 400. Fires after the existence and owner checks, after getPersonalProjectForUserOrFail resolves the to-be-deleted user's personal project.

Source

Thrown at packages/cli/src/controllers/users.controller.ts:257

			relations: ['role'],
		});

		if (!userToDelete) {
			throw new NotFoundError(
				'Request to delete a user failed because the user to delete was not found in DB',
			);
		}

		if (userToDelete.role.slug === GLOBAL_OWNER_ROLE.slug) {
			throw new ForbiddenError('Instance owner cannot be deleted.');
		}

		const personalProjectToDelete = await this.projectRepository.getPersonalProjectForUserOrFail(
			userToDelete.id,
		);

		if (transferId === personalProjectToDelete.id) {
			throw new BadRequestError(
				'Request to delete a user failed because the user to delete and the transferee are the same user',
			);
		}

		let transfereeId;
		let transfereeProject: Project | null = null;

		if (transferId) {
			transfereeProject = await this.projectRepository.findOneBy({ id: transferId });

			if (!transfereeProject) {
				throw new NotFoundError(
					'Request to delete a user failed because the transferee project was not found in DB',
				);
			}

			const transfereeProjectId = transfereeProject.id;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Pass a transferId that belongs to a different user's personal project (or a shared project).
  2. If you have only the transferee user id, resolve their personal project first via GET /users/<transferee-id> and use that project id.
  3. Omit transferId entirely if you do not want to transfer (only do so if the user owns nothing).

Example fix

// before
DELETE /users/123?transferId=<user-123-personal-project-id>
// after
DELETE /users/123?transferId=<user-456-personal-project-id>
Defensive patterns

Strategy: validation

Validate before calling

function pickTransferProject(targetUserPersonalProjectId: string, candidates: string[]) {
  return candidates.find((p) => p !== targetUserPersonalProjectId)
    ?? (() => { throw new Error('transferee must differ from the deleted user'); })();
}
// pass a different user's personal project id as ?transferId=

Try / catch

try { await fetch(`/rest/users/${id}?transferId=${pid}`, { method: 'DELETE' }); }
catch (e) { if (e.statusCode === 400 && /same user/.test(e.message)) { /* pick another project */ } else throw e; }

Prevention

When it happens

Trigger: DELETE /users/<id>?transferId=<that-user's-personal-project-id>. The transfer target resolves to the user's own personal project.

Common situations: UI defaulting the transferee picker to the same user; client computing transferId from the target user's profile; misunderstanding that transferId is a project id, not a user id, and passing the target's personal-project id.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/3aafa44969d738ec. Report an issue: GitHub.