When implementing exception handling (try-except), there are cases where you don’t want to “resolve the error on the spot,” but rather “log the fact that an error occurred and leave the actual handling to the caller (higher-level process).”
In such cases, “Re-raising” the exception is effective. By intentionally raising the captured exception again, you can propagate the error information to the upper level without suppressing it.
This article explains how to re-raise exceptions using the raise statement and how to correctly preserve the traceback (information about where the error occurred).
What is Re-raising?
When an exception is caught in a try-except block, the error is usually considered “resolved” there, and the program continues with subsequent processing. However, for critical errors occurring within a function, you often need to notify the side calling the function that “an error has occurred,” rather than completing the process within the function itself. At this time, you use the raise statement inside the except block.
The Correct Way to Re-raise: raise Without Arguments
When re-raising an exception, the most recommended method is to write raise alone without specifying any arguments.
Syntax:
try:
# Processing
except Exception:
# Log output, etc.
raise # Re-raise the caught exception as is
Specific Example
Let’s take a function that reads a configuration value and converts it to a number as an example. If the conversion fails, it outputs an error log and re-raises the exception to notify the entire system of the abnormality.
def parse_configuration(config_value):
"""
Function to convert configuration value to integer
"""
try:
# Convert string to integer (ValueError if failed)
result = int(config_value)
return result
except ValueError:
# 1. Detect error here and output log
print(f"[Log] Failed to convert config value. Value: {config_value}")
# 2. Re-raise the exception (Notify caller of error)
raise
# --- Main Processing ---
print("Starting process.")
try:
# Pass invalid value (string) to execute function
value = parse_configuration("InvalidNumber")
except ValueError:
# 3. Catch the re-raised exception at the caller
print("[System] Processing interrupted due to config error.")
print("Process finished.")
Output:
Starting process.
[Log] Failed to convert config value. Value: InvalidNumber
[System] Processing interrupted due to config error.
Process finished.
This flow achieves both “logging within the function” and “error handling (interruption) at the caller.”
Difference Between raise e and raise
It is possible to receive the exception object in a variable and re-raise it like raise e.
except ValueError as e:
print("Logging")
raise e # Specify variable to re-raise
However, if you simply want to throw the original exception upwards, using raise without arguments is recommended.
raise(no arguments): Preserves the “traceback (history such as line numbers where the error occurred)” of the generated exception as is. It makes the initial error location clear during debugging.raise e: Depending on the situation and Python version, the traceback information might be overwritten or treated as a chained exception, making it potentially harder to trace where the initial error occurred (unless that is your specific intent).
Summary
- Use “Re-raising” when you want to perform logging or temporary cleanup after catching an exception, but want to leave the error handling itself to the upper-level process.
- You can re-raise the currently caught exception as is by simply writing
raiseinside theexceptblock. - This allows you to propagate error information while accurately maintaining the error location (traceback).
