fix(core): Don't swallow connection errors when fetching credentials (#16181)

This commit is contained in:
Danny Martini
2025-06-11 10:08:09 +02:00
committed by GitHub
parent 2a3fa5088e
commit 9f83fccac1
2 changed files with 32 additions and 3 deletions

View File

@@ -1,3 +1,5 @@
import { CredentialsEntity, type CredentialsRepository } from '@n8n/db';
import { EntityNotFoundError } from '@n8n/typeorm';
import { mock } from 'jest-mock-extended';
import type {
IAuthenticateGeneric,
@@ -12,20 +14,43 @@ import { deepCopy, Workflow } from 'n8n-workflow';
import { CredentialTypes } from '@/credential-types';
import { CredentialsHelper } from '@/credentials-helper';
import { CredentialNotFoundError } from '@/errors/credential-not-found.error';
import type { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
describe('CredentialsHelper', () => {
const nodeTypes = mock<INodeTypes>();
const mockNodesAndCredentials = mock<LoadNodesAndCredentials>();
const credentialsRepository = mock<CredentialsRepository>();
const credentialsHelper = new CredentialsHelper(
new CredentialTypes(mockNodesAndCredentials),
mock(),
mock(),
credentialsRepository,
mock(),
mock(),
);
describe('getCredentials', () => {
test('turns `EntityNotFoundError` into `CredentialNotFoundError`s', async () => {
credentialsRepository.findOneByOrFail.mockRejectedValueOnce(
new EntityNotFoundError(CredentialsEntity, 'foo'),
);
await expect(
credentialsHelper.getCredentials({ id: '1', name: 'foo' }, 'bar'),
).rejects.toThrow(CredentialNotFoundError);
});
test('passes other error through', async () => {
const errorMessage = 'Connection terminated due to connection timeout';
credentialsRepository.findOneByOrFail.mockRejectedValueOnce(new Error(errorMessage));
await expect(
credentialsHelper.getCredentials({ id: '1', name: 'foo' }, 'bar'),
).rejects.toThrow(errorMessage);
});
});
describe('authenticate', () => {
const tests: Array<{
description: string;

View File

@@ -6,7 +6,7 @@ import type { CredentialsEntity, ICredentialsDb } from '@n8n/db';
import { CredentialsRepository, SharedCredentialsRepository } from '@n8n/db';
import { Service } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
import { EntityNotFoundError, In } from '@n8n/typeorm';
import { Credentials, getAdditionalKeys } from 'n8n-core';
import type {
ICredentialDataDecryptedObject,
@@ -257,7 +257,11 @@ export class CredentialsHelper extends ICredentialsHelper {
type,
});
} catch (error) {
throw new CredentialNotFoundError(nodeCredential.id, type);
if (error instanceof EntityNotFoundError) {
throw new CredentialNotFoundError(nodeCredential.id, type);
}
throw error;
}
return new Credentials(