n8n-io/n8n · error · UserError

The credential with ID "${workflow.id}" is already owned by

Error message

The credential with ID "${workflow.id}" is already owned by ${currentOwner}. It can't be re-owned by ${newOwner}.

What it means

Thrown by `import:workflow` (workflow.ts:146) via `throw new UserError(result.message)` where result comes from checkRelations. The message is built at workflow.ts:197 and says 'credential' even though this is the workflow import path — a copy-paste artefact: the workflow already exists in the DB and is owned by a different project/user than the one being imported into. Re-assignment of ownership is blocked to prevent silently moving workflows between projects.

Source

Thrown at packages/cli/src/commands/import/workflow.ts:146

			throw new UserError(
				'You cannot use `--userId` and `--projectId` together. Use one or the other.',
			);
		}

		const project = await this.getProject(flags.userId, flags.projectId);

		const ownerUser = await Container.get(UserRepository).findOneByOrFail({
			role: { slug: GLOBAL_OWNER_ROLE.slug },
		});
		// This userId will be used as the actor for publish/unpublish workflow actions
		const userId = flags.userId ?? ownerUser.id;

		const workflows = await this.readWorkflows(flags.input, flags.separate);

		const result = await this.checkRelations(workflows, flags.projectId, flags.userId);

		if (!result.success) {
			throw new UserError(result.message);
		}

		this.logger.info(`Importing ${workflows.length} workflows...`);

		await Container.get(ImportService).importWorkflows(workflows, project.id, userId, {
			activeState: flags.activeState,
		});

		this.reportSuccess(workflows.length);

		Container.get(EventService).emit('server-cli-import', {
			activeState: flags.activeState,
			workflowCount: workflows.length,
			separate: flags.separate,
		});
	}

	private async checkRelations(workflows: IWorkflowBase[], projectId?: string, userId?: string) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Import into the project that already owns the workflow: match --projectId to the current owner.
  2. Remove the `id` field from the import JSON so a fresh workflow is created.
  3. Delete the existing workflow first, then import.
  4. Drop --userId/--projectId entirely to fall back to the original owner.

Example fix

// before — workflow id 'X' owned by project A, importing into project B
n8n import:workflow --input=f.json --projectId=B
// after — let n8n create a new workflow instead
// edit f.json to remove "id": "X", then:
n8n import:workflow --input=f.json --projectId=B
Defensive patterns

Strategy: validation

Validate before calling

async function workflowOwnershipMatches(ds: DataSource, workflowId: string, targetProjectId?: string): Promise<boolean> {
  if (!targetProjectId) return true;
  const sharing = await ds.getRepository('shared_workflow').findOne({ where: { workflowId, role: 'workflow:owner' } });
  return sharing?.projectId === targetProjectId;
}
for (const w of workflows) {
  if (w.id && !(await workflowOwnershipMatches(ds, w.id, flags.projectId))) {
    throw new Error(`Workflow ${w.id} already owned elsewhere — remove id or change target`);
  }
}

Prevention

When it happens

Trigger: `n8n import:workflow --input=f.json --projectId=B` where the JSON contains a workflow with an ID that already exists and is currently owned by project A (or user A's personal project). checkRelations at workflow.ts:164-206 detects the ownership mismatch.

Common situations: Re-importing a backup into a different project; migrating workflows between environments where IDs collide; importing the same file twice with different --projectId flags.

Related errors


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