n8n-io/n8n · error · NotFoundError
404
404
Error message
Credential to be updated not found. You can only update credentials owned by you
What it means
Thrown inside the credential-update path when credentialsFinderService.findCredentialForUser(id,user,['credential:update'],{includeInstanceCredentials:true}) returns null — meaning no matching credential is visible to the user with the credential:update scope. HTTP 404. Like other credential errors, the message intentionally blends 'missing' and 'no-permission'. A logger.info records 'Attempt to update credential blocked due to lack of permissions' with the credentialId and userId.
Source
Thrown at packages/cli/src/credentials/credentials.controller.ts:255
const {
body,
user,
params: { credentialId },
} = req;
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' &&View on GitHub (pinned to 5ac6606e81)
Solutions
- Confirm via GET /credentials that the id is visible and that the user holds credential:update.
- Refresh access by being re-added to the owning project, or use a credential you own.
- Treat 404 here as terminal — do not retry without re-establishing access.
Defensive patterns
Strategy: validation
Validate before calling
async function canUpdateCredential(credentialId: string) {
const r = await fetch(`/rest/credentials/${credentialId}`, { method: 'GET' });
if (!r.ok) return false;
const c = await r.json();
return c.scopes?.includes('credential:update') ?? false;
}
if (!(await canUpdateCredential(id))) {
throw new Error('No credential:update on this credential');
} Type guard
const canUpdate = (c: { scopes?: string[] }) =>
Array.isArray(c.scopes) && c.scopes.includes('credential:update'); Try / catch
try { await fetch(`/rest/credentials/${id}`, { method: 'PUT', body }); }
catch (e) { if (e.statusCode === 404) { /* refresh or regain access */ } else throw e; } Prevention
- Confirm credential:update scope on the owning project before editing.
- Refresh the editor if the user's project membership changed.
- Treat 404 here as terminal.
When it happens
Trigger: PUT/PATCH /credentials/:id where :id does not exist OR exists but the user lacks credential:update on the owning project; also when includeInstanceCredentials:true still yields no row.
Common situations: User was removed from a project but still has the credential open in an editor tab; cross-tenant id; credential deleted; RBAC scope missing after migration.
Related errors
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0524d277bbfefed8.
Report an issue: GitHub.