n8n-io/n8n · error · UserError

Provider connection type cannot be changed. Create a new con

Error message

Provider connection type cannot be changed. Create a new connection instead.

What it means

Thrown by `import:credentials` storeCredential when an existing credential has `usageScope === 'instance'` (a provider connection) and the import payload sets `type` to a different value than the stored type. Instance-scope provider connections are immutable in type — you cannot morph a Slack credential into an HTTP credential by re-importing.

Source

Thrown at packages/cli/src/commands/import/credentials.ts:184

		credential: Partial<CredentialsEntity>,
		project: Project,
		ctx: OperationContext,
	) {
		// UsageScope is instance-local state; imports never change it for existing credentials.
		let existing: Pick<CredentialsEntity, 'id' | 'type' | 'usageScope'> | null = null;
		if (credential.id) {
			existing = await transactionManager.findOne(CredentialsEntity, {
				where: { id: credential.id },
				select: ['id', 'usageScope', 'type'],
			});
			if (existing) {
				credential.usageScope = existing.usageScope;
				if (
					existing.usageScope === 'instance' &&
					credential.type !== undefined &&
					credential.type !== existing.type
				) {
					throw new UserError(
						'Provider connection type cannot be changed. Create a new connection instead.',
					);
				}
			}
		}
		credential.usageScope ??= 'project';

		if (credential.usageScope === 'instance') {
			if (
				credential.isGlobal ||
				credential.isResolvable ||
				credential.isManaged ||
				credential.resolvableAllowFallback ||
				credential.resolverId
			) {
				throw new UserError(
					'Provider connections cannot be global, managed, or dynamically resolved',
				);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Change the import JSON's `type` to match the existing instance credential's type.
  2. Remove the `id` field from the import JSON so a new credential is created instead of updating.
  3. Delete the existing instance credential first, then import.

Example fix

// before — JSON has type: "httpBasicAuth" but DB has "slackApi"
// after — match the type, or drop the id
{ "id": "x", "type": "slackApi", "name": "..." }
Defensive patterns

Strategy: validation

Validate before calling

// Before importing, confirm the existing instance credential's type matches the import payload
async function typeMatches(ds: DataSource, id: string, importType: string): Promise<boolean> {
  const row = await ds.getRepository('credentials_entity').findOne({ where: { id }, select: ['type', 'usageScope'] });
  return row?.usageScope !== 'instance' || row.type === importType;
}
if (!(await typeMatches(ds, credential.id, credential.type))) {
  throw new Error('Type mismatch — drop the id or update the JSON type');
}

Prevention

When it happens

Trigger: Re-importing a credentials JSON file where a credential with the same ID exists as an instance credential but the JSON's `type` field differs. Common when the JSON was exported from a different credential type or hand-edited.

Common situations: Bulk re-import across environments where the credential type drifted; manual JSON edits; importing a backup that was created from a different credential and reusing the ID.

Related errors


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