n8n-io/n8n · warning · BadRequestError

400

400

Error message

Managed credentials cannot be updated

What it means

Thrown by the credential-update path when the resolved credential has isManaged === true. Managed credentials are provisioned externally (e.g. via config / deployment tooling) and are immutable from the API/UI to prevent drift. HTTP 400. Fires after the existence check, before auth-type/scope checks.

Source

Thrown at packages/cli/src/credentials/credentials.controller.ts:261

		const credential = await this.credentialsFinderService.findCredentialForUser(
			credentialId,
			user,
			['credential:update'],
			{ includeInstanceCredentials: true },
		);

		if (!credential) {
			this.logger.info('Attempt to update credential blocked due to lack of permissions', {
				credentialId,
				userId: user.id,
			});
			throw new NotFoundError(
				'Credential to be updated not found. You can only update credentials owned by you',
			);
		}

		if (credential.isManaged) {
			throw new BadRequestError('Managed credentials cannot be updated');
		}

		const isChangingAuthType = body.type !== undefined && body.type !== credential.type;

		if (credential.usageScope === 'instance' && isChangingAuthType) {
			throw new BadRequestError(
				'Provider connection type cannot be changed. Create a new connection instead.',
			);
		}

		if (
			credential.usageScope === 'instance' &&
			(body.isGlobal === true || body.isResolvable === true)
		) {
			throw new BadRequestError(
				'Provider connections cannot be globally shared or converted to end-user credentials',
			);
		}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Update the managed credential at its source (config/deployment manifest), not via the API.
  2. If user-editable is required, create a new non-managed credential and migrate references.
  3. Surface isManaged in the UI to disable the edit affordance.
Defensive patterns

Strategy: type-guard

Validate before calling

function assertEditable(c: { isManaged?: boolean }) {
  if (c.isManaged) throw new Error('Managed credential; edit at source config');
}
// fetch credential, then assertEditable(credential) before PUT/PATCH

Type guard

const isEditableCredential = (c: { isManaged?: boolean }) => c.isManaged !== true;

Try / catch

try { await fetch(`/rest/credentials/${id}`, { method: 'PUT', body }); }
catch (e) { if (e.statusCode === 400 && /managed/i.test(e.message)) { /* edit at source */ } else throw e; }

Prevention

When it happens

Trigger: PUT/PATCH /credentials/:id on a credential flagged isManaged (typically deployed via N8N_CREDENTIALS_* or instance-config tooling); any field update triggers the guard.

Common situations: Operator edits a managed credential in the UI thinking it is user-owned; automation that loops over all credentials and PATCHes them; environment where managed credentials were introduced after the editor UI cached the row.

Related errors


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