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
- Omit the type field from the update (keep the existing type).
- If a different auth method is required, create a new instance credential of the new type and delete the old one.
- 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
- Pin the type to the existing value when updating instance credentials.
- Create a new credential to switch auth methods.
- Disable type editing in the form for instance/provider connections.
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
- 0
- Azure AI Search endpoint is missing or invalid
- Expected Supabase credentials host to be a string
- Provider connection data cannot be empty
- Provider connection data must be a JSON object
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/3f01e1a9ffdfdba9.
Report an issue: GitHub.