@@ -294,21 +294,23 @@ async function runCodexExecResume(params: {
294294 child . stdout . on ( "data" , ( chunk : Buffer ) => stdout . push ( chunk ) ) ;
295295 child . stderr . on ( "data" , ( chunk : Buffer ) => stderr . push ( chunk ) ) ;
296296 child . stdin . end ( params . prompt ) ;
297+ let streamError : Error | undefined ;
297298 const exitCode = await new Promise < number | null > ( ( resolve , reject ) => {
298299 child . on ( "error" , reject ) ;
299300 child . on ( "exit" , ( code ) => resolve ( code ) ) ;
300301 // Guard against unhandled EPIPE / read-failure errors on the parent-side
301302 // stdout/stderr Readable. When the child terminates abruptly the pipe
302303 // can break before the "exit" event fires, so the stream layer emits
303304 // an asynchronous "error" that would otherwise crash the gateway.
305+ // Unlike the earlier pattern of rejecting immediately, we record the
306+ // error and wait for the child to exit via the existing exit-listener so
307+ // the caller's active-session guard is not released while the child
308+ // process is still running.
304309 const routeStreamError = ( error : unknown ) => {
305- // Kill the child before surfacing the stream error so the caller's
306- // active-session guard is not released while the child is still running
307- // and the process does not become orphaned.
310+ streamError = error instanceof Error ? error : new Error ( String ( error ) ) ;
308311 child . kill ( "SIGTERM" ) ;
309312 const sigkill = setTimeout ( ( ) => child . kill ( "SIGKILL" ) , 2_000 ) ;
310313 sigkill . unref ( ) ;
311- reject ( error instanceof Error ? error : new Error ( String ( error ) ) ) ;
312314 } ;
313315 child . stdout ?. on ?.( "error" , routeStreamError ) ;
314316 child . stderr ?. on ?.( "error" , routeStreamError ) ;
@@ -318,6 +320,9 @@ async function runCodexExecResume(params: {
318320 clearTimeout ( forceKillTimeout ) ;
319321 }
320322 } ) ;
323+ if ( streamError ) {
324+ throw streamError ;
325+ }
321326 if ( timedOut ) {
322327 throw new Error ( `codex exec resume timed out after ${ String ( params . timeoutMs ) } ms` ) ;
323328 }
0 commit comments