@@ -71,9 +71,21 @@ export class BlockExecutor {
7171
7272 try {
7373 resolvedInputs = this . resolver . resolveInputs ( ctx , node . id , block . config . params , block )
74- } finally {
74+ } catch ( error ) {
7575 cleanupSelfReference ?.( )
76+ return this . handleBlockError (
77+ error ,
78+ ctx ,
79+ node ,
80+ block ,
81+ startTime ,
82+ blockLog ,
83+ resolvedInputs ,
84+ isSentinel ,
85+ 'input_resolution'
86+ )
7687 }
88+ cleanupSelfReference ?.( )
7789
7890 try {
7991 const output = handler . executeWithNode
@@ -120,58 +132,17 @@ export class BlockExecutor {
120132
121133 return normalizedOutput
122134 } catch ( error ) {
123- const duration = Date . now ( ) - startTime
124- const errorMessage = normalizeError ( error )
125-
126- if ( blockLog ) {
127- blockLog . endedAt = new Date ( ) . toISOString ( )
128- blockLog . durationMs = duration
129- blockLog . success = false
130- blockLog . error = errorMessage
131- }
132-
133- const errorOutput : NormalizedBlockOutput = {
134- error : errorMessage ,
135- }
136-
137- this . state . setBlockOutput ( node . id , errorOutput , duration )
138-
139- logger . error ( 'Block execution failed' , {
140- blockId : node . id ,
141- blockType : block . metadata ?. id ,
142- error : errorMessage ,
143- } )
144-
145- if ( ! isSentinel ) {
146- this . callOnBlockComplete ( ctx , node , block , resolvedInputs , errorOutput , duration )
147- }
148-
149- const hasErrorPort = this . hasErrorPortEdge ( node )
150-
151- if ( hasErrorPort ) {
152- logger . info ( 'Block has error port - returning error output instead of throwing' , {
153- blockId : node . id ,
154- error : errorMessage ,
155- } )
156- return errorOutput
157- }
158-
159- let errorToThrow : Error | string
160- if ( error instanceof Error ) {
161- errorToThrow = error
162- } else {
163- errorToThrow = errorMessage
164- }
165-
166- throw buildBlockExecutionError ( {
135+ return this . handleBlockError (
136+ error ,
137+ ctx ,
138+ node ,
167139 block ,
168- error : errorToThrow ,
169- context : ctx ,
170- additionalInfo : {
171- nodeId : node . id ,
172- executionTime : duration ,
173- } ,
174- } )
140+ startTime ,
141+ blockLog ,
142+ resolvedInputs ,
143+ isSentinel ,
144+ 'execution'
145+ )
175146 }
176147 }
177148
@@ -196,6 +167,68 @@ export class BlockExecutor {
196167 return this . blockHandlers . find ( ( h ) => h . canHandle ( block ) )
197168 }
198169
170+ private handleBlockError (
171+ error : unknown ,
172+ ctx : ExecutionContext ,
173+ node : DAGNode ,
174+ block : SerializedBlock ,
175+ startTime : number ,
176+ blockLog : BlockLog | undefined ,
177+ resolvedInputs : Record < string , any > ,
178+ isSentinel : boolean ,
179+ phase : 'input_resolution' | 'execution'
180+ ) : NormalizedBlockOutput {
181+ const duration = Date . now ( ) - startTime
182+ const errorMessage = normalizeError ( error )
183+
184+ if ( blockLog ) {
185+ blockLog . endedAt = new Date ( ) . toISOString ( )
186+ blockLog . durationMs = duration
187+ blockLog . success = false
188+ blockLog . error = errorMessage
189+ }
190+
191+ const errorOutput : NormalizedBlockOutput = {
192+ error : errorMessage ,
193+ }
194+
195+ this . state . setBlockOutput ( node . id , errorOutput , duration )
196+
197+ logger . error (
198+ phase === 'input_resolution' ? 'Failed to resolve block inputs' : 'Block execution failed' ,
199+ {
200+ blockId : node . id ,
201+ blockType : block . metadata ?. id ,
202+ error : errorMessage ,
203+ }
204+ )
205+
206+ if ( ! isSentinel ) {
207+ this . callOnBlockComplete ( ctx , node , block , resolvedInputs , errorOutput , duration )
208+ }
209+
210+ const hasErrorPort = this . hasErrorPortEdge ( node )
211+ if ( hasErrorPort ) {
212+ logger . info ( 'Block has error port - returning error output instead of throwing' , {
213+ blockId : node . id ,
214+ error : errorMessage ,
215+ } )
216+ return errorOutput
217+ }
218+
219+ const errorToThrow = error instanceof Error ? error : new Error ( errorMessage )
220+
221+ throw buildBlockExecutionError ( {
222+ block,
223+ error : errorToThrow ,
224+ context : ctx ,
225+ additionalInfo : {
226+ nodeId : node . id ,
227+ executionTime : duration ,
228+ } ,
229+ } )
230+ }
231+
199232 private hasErrorPortEdge ( node : DAGNode ) : boolean {
200233 for ( const [ _ , edge ] of node . outgoingEdges ) {
201234 if ( edge . sourceHandle === EDGE . ERROR ) {
0 commit comments