@@ -282,6 +282,23 @@ def exec_in_proc(group=None, target=None, name=None, args=(), kwargs={}, *, daem
282282 _logger .error ('remote traceback: %s' , result ['traceback' ])
283283 raise SubprocessExecutionError (p .pid or 0 , target_name , p .exitcode or 1 , details )
284284
285+ # If we received a valid result payload, return it even if the exit
286+ # code is non-zero. The non-zero code typically comes from
287+ # multiprocessing/C-extension cleanup (e.g. util._exit_function or
288+ # a native atexit handler) that runs *after* exception_wrap has
289+ # already sent the result over the pipe.
290+ if result is not None and 'value' in result :
291+ if p .exitcode not in (None , 0 ):
292+ _logger .warning (
293+ 'Subprocess PID %d for %s exited with code %s after %.2f ms'
294+ ' but returned a valid result — accepting the result.'
295+ ' The non-zero exit likely originates from process'
296+ ' cleanup (multiprocessing finalizers, C-extension'
297+ ' atexit, etc.).' ,
298+ p .pid , target_name , p .exitcode , elapsed_ms ,
299+ )
300+ return result ['value' ]
301+
285302 if p .exitcode and p .exitcode < 0 :
286303 _logger .warning (
287304 'Subprocess PID %d for %s exited due to signal %d after %.2f ms' ,
@@ -297,15 +314,12 @@ def exec_in_proc(group=None, target=None, name=None, args=(), kwargs={}, *, daem
297314 'No structured exception payload received from child process' ,
298315 )
299316
300- if result is None :
301- raise SubprocessExecutionError (
302- p .pid or 0 ,
303- target_name ,
304- 0 ,
305- 'Subprocess exited successfully but returned no result payload' ,
306- )
307-
308- return result ['value' ]
317+ raise SubprocessExecutionError (
318+ p .pid or 0 ,
319+ target_name ,
320+ 0 ,
321+ 'Subprocess exited successfully but returned no result payload' ,
322+ )
309323
310324
311325def timed (func : Callable ):
0 commit comments