n8n-io/n8n · error · BadRequestError

400

400

Error message

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

What it means

Thrown by CredentialsService.updateInstanceCredential when the prepared update data has a type different from the existing credential's type. Instance/provider connections are immutable in type: changing auth method (e.g. service-account -> OAuth) requires creating a new connection. This is the service-level duplicate of the controller-level check at credentials.controller.ts:266.

Source

Thrown at packages/cli/src/credentials/credentials.service.ts:1053

		options: InstanceCredentialWriteOptions = {},
	): Promise<CredentialsEntity> {
		if (!hasGlobalScope(user, 'credential:manageInstance')) {
			throw new ForbiddenError('You do not have permission to update provider connections');
		}

		const credential = await this.credentialsRepository.findInstanceCredentialById(
			credentialId,
			ctx,
		);
		if (!credential) {
			throw new NotFoundError(`Credential with ID "${credentialId}" could not be found.`);
		}

		const prepared = await this.prepareUpdateData(user, data, credential, {
			operationContext: ctx,
		});
		if (prepared.type !== credential.type) {
			throw new BadRequestError(
				'Provider connection type cannot be changed. Create a new connection instead.',
			);
		}
		const decryptedData = prepared.data as unknown as ICredentialDataDecryptedObject;
		const encrypted =
			options.encryptedData ??
			(await this.createEncryptedData({
				id: credential.id,
				name: prepared.name,
				type: prepared.type,
				data: decryptedData,
			}));
		if (!options.skipExternalHooks) {
			await this.externalHooks.run('credentials.update', [encrypted]);
		}
		const hookedData = await this.getValidatedInstanceCredentialHookData(
			encrypted,
			credential.id,

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Omit the type field from the update (keep the existing type).
  2. If a different auth method is required, create a new instance credential of the new type and delete the old one.
  3. Validate that body.type === credential.type before sending.

Example fix

// before
await updateInstanceCredential(id, { type: 'googleOAuth2Api', ... });

// after
if (body.type && body.type !== existing.type) {
  await createInstanceCredential({ type: body.type, ... });
} else {
  await updateInstanceCredential(id, { ...body, type: undefined });
}
Defensive patterns

Strategy: validation

Validate before calling

if (body.type && body.type !== existing.type) {
  throw new Error('Type change not allowed for instance credentials — create new.');
}
const patch = { ...body, type: existing.type };
await updateInstanceCredential(user, id, patch, ctx);

Prevention

When it happens

Trigger: Calling updateInstanceCredential with a body whose type differs from the stored credential.type — e.g. sending 'googleOAuth2Api' for a credential stored as 'googleApi'.

Common situations: Frontend reuses an edit form that allows type changes for project credentials against an instance credential. Migration script attempting to normalize credential types in place.

Related errors


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