diff --git a/packages/nodes-base/nodes/Code/ExecutionError.ts b/packages/nodes-base/nodes/Code/ExecutionError.ts index e1fdffc0b6..53e87fc2e7 100644 --- a/packages/nodes-base/nodes/Code/ExecutionError.ts +++ b/packages/nodes-base/nodes/Code/ExecutionError.ts @@ -28,15 +28,16 @@ export class ExecutionError extends ApplicationError { * Populate error `message` and `description` from error `stack`. */ private populateFromStack() { - const stackRows = this.stack.split('\n'); + const stackRows = this.stack && typeof this.stack === 'string' ? this.stack.split('\n') : []; if (stackRows.length === 0) { this.message = 'Unknown error'; + return; } const messageRow = stackRows.find((line) => line.includes('Error:')); const lineNumberRow = stackRows.find((line) => line.includes('Code:')); - const lineNumberDisplay = this.toLineNumberDisplay(lineNumberRow); + const lineNumberDisplay = this.toLineNumberDisplay(lineNumberRow) || ''; if (!messageRow) { this.message = `Unknown error ${lineNumberDisplay}`; @@ -52,7 +53,7 @@ export class ExecutionError extends ApplicationError { return; } - this.message = `${errorDetails} ${lineNumberDisplay}`; + this.message = `${errorDetails} ${lineNumberDisplay}`.trim(); } private toLineNumberDisplay(lineNumberRow?: string) { @@ -74,10 +75,16 @@ export class ExecutionError extends ApplicationError { private toErrorDetailsAndType(messageRow?: string) { if (!messageRow) return [null, null]; - const [errorDetails, errorType] = messageRow - .split(':') - .reverse() - .map((i) => i.trim()); + // Remove "Error: " prefix added by stacktrace formatting + messageRow = messageRow.replace(/^Error: /, ''); + + const colonIndex = messageRow.indexOf(': '); + if (colonIndex === -1) { + return [messageRow.trim(), null]; + } + + const errorType = messageRow.substring(0, colonIndex).trim(); + const errorDetails = messageRow.substring(colonIndex + 2).trim(); return [errorDetails, errorType === 'Error' ? null : errorType]; } diff --git a/packages/nodes-base/nodes/Code/test/ExecutionError.test.ts b/packages/nodes-base/nodes/Code/test/ExecutionError.test.ts new file mode 100644 index 0000000000..5d82c9b364 --- /dev/null +++ b/packages/nodes-base/nodes/Code/test/ExecutionError.test.ts @@ -0,0 +1,64 @@ +import { ExecutionError } from '../ExecutionError'; + +describe('ExecutionError', () => { + describe('constructor', () => { + it('should set message to "Unknown error" when stack is empty', () => { + const error = new Error('test'); + error.stack = ''; + const executionError = new ExecutionError(error); + expect(executionError.message).toBe('Unknown error'); + }); + + it('should extract error details and type from stack', () => { + const error = new Error('ErrorType: Error Details'); + error.stack = 'Error: ErrorType: Error Details\n at Code:123'; + const executionError = new ExecutionError(error); + expect(executionError.message).toBe('Error Details [line 123]'); + expect(executionError.description).toBe('ErrorType'); + }); + + it('should extract error details when no error type is present', () => { + const error = new Error('Error Details'); + error.stack = 'Error: Error Details\n at Code:123'; + const executionError = new ExecutionError(error); + expect(executionError.message).toBe('Error Details [line 123]'); + expect(executionError.description).toBe(null); + }); + + it('should handle stack with only "Error: " prefix', () => { + const error = new Error('Error: '); + error.stack = 'Error: Error: \n at Code:123'; + const executionError = new ExecutionError(error); + expect(executionError.message).toBe('Unknown error [line 123]'); + expect(executionError.description).toBe(null); + }); + + it('should handle stack with colon and space', () => { + const error = new Error(': '); + error.stack = 'Error: : \n at Code:123'; + const executionError = new ExecutionError(error); + expect(executionError.message).toBe('Unknown error [line 123]'); + expect(executionError.description).toBe(null); + }); + + it('should handle itemIndex', () => { + const error = new Error('ErrorType: Error Details'); + error.stack = 'Error: ErrorType: Error Details\n at Code:123'; + const executionError = new ExecutionError(error, 1); + expect(executionError.message).toBe('Error Details [line 123, for item 1]'); + expect(executionError.description).toBe('ErrorType'); + expect(executionError.itemIndex).toBe(1); + expect(executionError.context).toEqual({ itemIndex: 1 }); + }); + + it('should handle stack without line number', () => { + const error = new Error('ErrorType: Error Details'); + error.stack = 'Error: ErrorType: Error Details'; + const executionError = new ExecutionError(error, 1); + expect(executionError.message).toBe('Error Details'); + expect(executionError.description).toBe('ErrorType'); + expect(executionError.itemIndex).toBe(1); + expect(executionError.context).toEqual({ itemIndex: 1 }); + }); + }); +});