mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 19:32:15 +00:00
fix(editor): Improve sub-workflow debugging for more node error types (#14347)
This commit is contained in:
@@ -2,6 +2,11 @@ import { isObjectLiteral } from 'n8n-core';
|
|||||||
import { NodeOperationError } from 'n8n-workflow';
|
import { NodeOperationError } from 'n8n-workflow';
|
||||||
import type { Workflow } from 'n8n-workflow';
|
import type { Workflow } from 'n8n-workflow';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional properties that should be propagated from an error object to the new Error instance.
|
||||||
|
*/
|
||||||
|
const errorProperties = ['description', 'stack', 'executionId', 'workflowId'];
|
||||||
|
|
||||||
export function objectToError(errorObject: unknown, workflow: Workflow): Error {
|
export function objectToError(errorObject: unknown, workflow: Workflow): Error {
|
||||||
// TODO: Expand with other error types
|
// TODO: Expand with other error types
|
||||||
if (errorObject instanceof Error) {
|
if (errorObject instanceof Error) {
|
||||||
@@ -34,15 +39,11 @@ export function objectToError(errorObject: unknown, workflow: Workflow): Error {
|
|||||||
error = new Error(errorObject.message);
|
error = new Error(errorObject.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('description' in errorObject) {
|
for (const field of errorProperties) {
|
||||||
// @ts-expect-error Error descriptions are surfaced by the UI but
|
if (field in errorObject && errorObject[field]) {
|
||||||
// not all backend errors account for this property yet.
|
// Not all errors contain these properties
|
||||||
error.description = errorObject.description as string;
|
(error as unknown as Record<string, unknown>)[field] = errorObject[field];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('stack' in errorObject) {
|
|
||||||
// If there's a 'stack' property, set it on the new Error instance.
|
|
||||||
error.stack = errorObject.stack as string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|||||||
@@ -27,5 +27,8 @@ export function parseErrorMetadata(error: unknown): ISubWorkflowMetadata | undef
|
|||||||
if (hasKey(error, 'errorResponse')) {
|
if (hasKey(error, 'errorResponse')) {
|
||||||
return parseErrorResponseWorkflowMetadata(error.errorResponse);
|
return parseErrorResponseWorkflowMetadata(error.errorResponse);
|
||||||
}
|
}
|
||||||
return undefined;
|
|
||||||
|
// This accounts for cases where the backend attaches the properties on plain errors
|
||||||
|
// e.g. from custom nodes throwing literal `Error` or `ApplicationError` objects directly
|
||||||
|
return parseErrorResponseWorkflowMetadata(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,38 @@ import { parseErrorMetadata } from '@/MetadataUtils';
|
|||||||
|
|
||||||
describe('MetadataUtils', () => {
|
describe('MetadataUtils', () => {
|
||||||
describe('parseMetadataFromError', () => {
|
describe('parseMetadataFromError', () => {
|
||||||
it('should return undefined if error does not have response', () => {
|
const expectedMetadata = {
|
||||||
|
subExecution: {
|
||||||
|
executionId: '123',
|
||||||
|
workflowId: '456',
|
||||||
|
},
|
||||||
|
subExecutionsCount: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return undefined if error does not have response or both keys on the object', () => {
|
||||||
const error = { message: 'An error occurred' };
|
const error = { message: 'An error occurred' };
|
||||||
const result = parseErrorMetadata(error);
|
const result = parseErrorMetadata(error);
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return undefined if errorResponse only has workflowId key', () => {
|
||||||
|
const error = { errorResponse: { executionId: '123' } };
|
||||||
|
const result = parseErrorMetadata(error);
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined if error only has executionId key', () => {
|
||||||
|
const error = { executionId: '123' };
|
||||||
|
const result = parseErrorMetadata(error);
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support executionId and workflowId key directly on the error object', () => {
|
||||||
|
const error = { executionId: '123', workflowId: '456' };
|
||||||
|
const result = parseErrorMetadata(error);
|
||||||
|
expect(result).toEqual(expectedMetadata);
|
||||||
|
});
|
||||||
|
|
||||||
it('should return undefined if error response does not have subworkflow data', () => {
|
it('should return undefined if error response does not have subworkflow data', () => {
|
||||||
const error = { errorResponse: { someKey: 'someValue' } };
|
const error = { errorResponse: { someKey: 'someValue' } };
|
||||||
const result = parseErrorMetadata(error);
|
const result = parseErrorMetadata(error);
|
||||||
@@ -16,13 +42,6 @@ describe('MetadataUtils', () => {
|
|||||||
|
|
||||||
it('should return metadata if error response has subworkflow data', () => {
|
it('should return metadata if error response has subworkflow data', () => {
|
||||||
const error = { errorResponse: { executionId: '123', workflowId: '456' } };
|
const error = { errorResponse: { executionId: '123', workflowId: '456' } };
|
||||||
const expectedMetadata = {
|
|
||||||
subExecution: {
|
|
||||||
executionId: '123',
|
|
||||||
workflowId: '456',
|
|
||||||
},
|
|
||||||
subExecutionsCount: 1,
|
|
||||||
};
|
|
||||||
const result = parseErrorMetadata(error);
|
const result = parseErrorMetadata(error);
|
||||||
expect(result).toEqual(expectedMetadata);
|
expect(result).toEqual(expectedMetadata);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user