@@ -186,6 +186,7 @@ class ErrorCodes:
186186 PROXYTOOSHORT = 1382 # used at the beginning of the pilot to indicate that the proxy is too short
187187 STAGEOUTAUTHENTICATIONFAILURE = 1383
188188 QUEUENOTSETUPFORCONTAINERS = 1384
189+ NOJOBSINPANDA = 1385 # internally used code
189190
190191 _error_messages = {
191192 GENERALERROR : "General pilot error, consult batch log" ,
@@ -333,7 +334,7 @@ class ErrorCodes:
333334 PROXYTOOSHORT : "Proxy is too short" ,
334335 STAGEOUTAUTHENTICATIONFAILURE : "Authentication failure during stage-out" ,
335336 QUEUENOTSETUPFORCONTAINERS : "Queue is not set up for containers" ,
336-
337+ NOJOBSINPANDA : "No jobs in PanDA" ,
337338 }
338339
339340 put_error_codes = [1135 , 1136 , 1137 , 1141 , 1152 , 1181 ]
@@ -344,11 +345,11 @@ def reset_pilot_errors(self):
344345 ErrorCodes .pilot_error_codes = []
345346 ErrorCodes .pilot_error_diags = []
346347
347- def get_kill_signal_error_code (self , signal : str ) -> int :
348+ def get_kill_signal_error_code (self , signal_name : str ) -> int :
348349 """
349350 Match a kill signal with a corresponding Pilot error code.
350351
351- :param signal : signal name (str).
352+ :param signal_name : signal name (str).
352353 :return: Pilot error code (int).
353354 """
354355 signals_dictionary = {
@@ -358,9 +359,10 @@ def get_kill_signal_error_code(self, signal: str) -> int:
358359 "SIGXCPU" : self .SIGXCPU ,
359360 "SIGUSR1" : self .SIGUSR1 ,
360361 "SIGBUS" : self .SIGBUS ,
362+ "SIGINT" : self .SIGINT ,
361363 }
362364
363- return signals_dictionary .get (signal , self .KILLSIGNAL )
365+ return signals_dictionary .get (signal_name , self .KILLSIGNAL )
364366
365367 def get_error_message (self , errorcode : int ) -> str :
366368 """
@@ -445,13 +447,17 @@ def report_errors(self) -> str:
445447
446448 return report
447449
448- def resolve_transform_error (self , exit_code : int , stderr : str ) -> int :
450+ def resolve_transform_error (self , exit_code : int , stderr : str ) -> tuple [ int , str ] :
449451 """
450452 Assign a pilot error code to a specific transform error.
451453
452- :param exit_code: transform exit code (int)
453- :param stderr: transform stderr (str)
454- :return: pilot error code (int).
454+ Args:
455+ exit_code (int): Transform exit code.
456+ stderr (str): Transform stderr.
457+
458+ Returns:
459+ int: Pilot error code.
460+ str: Error message if extracted from stderr, otherwise an empty string.
455461 """
456462 error_map = {
457463 "Not mounting requested bind point" : self .SINGULARITYBINDPOINTFAILURE ,
@@ -464,28 +470,51 @@ def resolve_transform_error(self, exit_code: int, stderr: str) -> int:
464470 "Apptainer is not installed" : self .APPTAINERNOTINSTALLED ,
465471 "cannot create directory" : self .MKDIR ,
466472 "General payload setup verification error" : self .SETUPFAILURE ,
473+ "No such file or directory" : self .NOSUCHFILE ,
467474 }
468475
476+ def get_key_by_value (d : dict , value : str ) -> str :
477+ """Return the key corresponding to a given value."""
478+ for k , v in d .items ():
479+ if v == value :
480+ return k
481+ return ""
482+
469483 # Check if stderr contains any known error messages
484+ apptainer_codes = {
485+ self .SINGULARITYBINDPOINTFAILURE ,
486+ self .SINGULARITYNOLOOPDEVICES ,
487+ self .SINGULARITYIMAGEMOUNTFAILURE ,
488+ self .SINGULARITYIMAGEMOUNTFAILURE ,
489+ self .SINGULARITYGENERALFAILURE ,
490+ self .SINGULARITYFAILEDUSERNAMESPACE ,
491+ self .SINGULARITYNOTINSTALLED ,
492+ self .APPTAINERNOTINSTALLED
493+ }
470494 for error_message , error_code in error_map .items ():
471495 if error_message in stderr :
472- return error_code
496+ # only allow overwriting exit code 0 for specific errors (read: apptainer)
497+ if exit_code == 0 and error_code in apptainer_codes :
498+ return error_code , error_message
499+ else :
500+ continue
473501
474502 # Handle specific exit codes
503+ key = get_key_by_value (error_map , exit_code )
475504 if exit_code == 2 :
476- return self .LSETUPTIMEDOUT
505+ return self .LSETUPTIMEDOUT , key
477506 if exit_code == 3 :
478- return self .REMOTEFILEOPENTIMEDOUT
507+ return self .REMOTEFILEOPENTIMEDOUT , key
479508 if exit_code == 251 :
480- return self .UNKNOWNTRFFAILURE
509+ return self .UNKNOWNTRFFAILURE , key
481510 if exit_code == - 1 :
482- return self .UNKNOWNTRFFAILURE
511+ return self .UNKNOWNTRFFAILURE , key
483512 if exit_code == self .COMMANDTIMEDOUT :
484- return exit_code
513+ return exit_code , key
485514 if exit_code != 0 :
486- return self .PAYLOADEXECUTIONFAILURE
515+ return self .PAYLOADEXECUTIONFAILURE , key
487516
488- return exit_code # Return original exit code if no specific error is found
517+ return exit_code , key # Return original exit code if no specific error is found
489518
490519 def extract_stderr_error (self , stderr : str ) -> str :
491520 """
0 commit comments