n8n-io/n8n · error · TransferCredentialError

400

400

Error message

You can't transfer a credential into the project that's already owning it.

What it means

Thrown by EnterpriseCredentialsService.transferOne when sourceProject.id === destinationProjectId. Transferring a credential to the project that already owns it is a no-op and is explicitly rejected. The check runs after both projects are resolved and access is verified, so the IDs are valid — just identical.

Source

Thrown at packages/cli/src/credentials/credentials.service.ee.ts:226

		);

		// 3. get source project
		const sourceProject = ownerSharing.project;

		// 4. get destination project
		const destinationProject = await this.projectService.getProjectWithScope(
			user,
			destinationProjectId,
			['credential:create'],
		);
		NotFoundError.isDefinedAndNotNull(
			destinationProject,
			`Could not find project with the id "${destinationProjectId}". Make sure you have the permission to create credentials in it.`,
		);

		// 5. checks
		if (sourceProject.id === destinationProject.id) {
			throw new TransferCredentialError(
				"You can't transfer a credential into the project that's already owning it.",
			);
		}

		// Transferring an end-user credential into a project is equivalent to creating
		// one there, so it must clear the same createEndUser gate.
		if (credential.isResolvable) {
			await this.credentialsService.ensureCanManageEndUserCredential(user, destinationProject.id);
		}

		// 6. validate that the destination project has access to all external secret providers
		if (
			this.licenseState.isExternalSecretsLicensed() &&
			this.externalSecretsConfig.externalSecretsForProjects
		) {
			const decryptedData = await this.credentialsService.decrypt(credential, true);
			await validateAccessToReferencedSecretProviders(
				destinationProject.id,

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Pass a destination project ID different from the current owning project.
  2. Fetch the current owner project first and skip the transfer if it equals the destination.
  3. Fix the form/selector so it cannot target the current owner.

Example fix

// before
await transferCredential(id, currentOwnerProjectId);

// after
if (destinationId !== currentOwnerProjectId) {
  await transferCredential(id, destinationId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (destinationProjectId === currentOwnerProjectId) {
  throw new Error('Destination equals current owner — nothing to transfer.');
}
await transferOne(user, id, destinationProjectId);

Prevention

When it happens

Trigger: POST transfer-ownership with a destinationProjectId equal to the credential's current owning project.

Common situations: UI defaulting the destination dropdown to the current owner. Caller re-issuing a transfer after a partial success. Mis-routed automation passing the source project as destination.

Related errors


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