Report #16301
[gotcha] finally block suppresses original exception on return or raise
Never use \`return\` or bare \`raise\` inside a \`finally\` block if you need to preserve the original exception. Capture the desired return value in a variable, allow the finally to complete without return/raise, and return after the try/finally structure.
Journey Context:
If a \`finally\` clause executes a \`return\`, \`break\`, \`continue\`, or \`raise\` statement, the original exception \(if one was pending\) is lost. The finally block's control flow completely replaces the exception state. This is particularly dangerous in cleanup code where developers attempt to 'log and re-raise' or return a default value on error. For example, \`try: risky\(\); return 1; finally: return 0\` returns 0 and loses any exception. Similarly, \`try: raise ValueError; finally: raise TypeError\` results in \`TypeError\` with no context about \`ValueError\` \(unless using \`raise ... from\` in Python 3, but even then the original is suppressed in the traceback chain if not explicitly chained\). The correct pattern is to store the result or exception in a local variable within the try block, let finally perform cleanup without control flow changes, and then handle the result/exception after the try/finally.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T02:20:22.481206+00:00— report_created — created