Repository: PaddlePaddle/Paddle
Pull request #72784: [SOT][Exception] Add exception test && fix some param annotation
Author: login: DrRyanHuang
Labels: name: contributor
description: External developers
Created: 2025-05-19T07:39:19Z | Merged: 2025-05-26T07:39:08Z

<!-- TemplateReference: https://github.com/PaddlePaddle/Paddle/wiki/PULL-REQUEST-TEMPLATE--REFERENCE -->
<!-- Demo: https://github.com/PaddlePaddle/Paddle/pull/24810 -->

### PR Category
<!-- One of [ User Experience | Execute Infrastructure | Operator Mechanism | CINN | Custom Device | Performance Optimization | Distributed Strategy | Parameter Server | Communication Library | Auto Parallel | Inference | Environment Adaptation ] -->
Execute Infrastructure

### PR Types
<!-- One of [ New features | Bug fixes | Improvements | Performance | BC Breaking | Deprecations | Docs | Devs | Not User Facing | Security | Others ] -->
Improvements

### Description
<!-- Describe what you’ve done -->
- 添加之前[PR72559](https://github.com/PaddlePaddle/Paddle/pull/72559)的单测，以及修复[PR72559](https://github.com/PaddlePaddle/Paddle/pull/72559)中review的部分问题
- 统一 `ExceptionVariable` 的设计，只有 `Exception` 才能直接创建 `ExceptionVariable`，不能传入 `type[Exception]` 与 `args` 后，由 `ExceptionVariable` 创建
- [PR72559](https://github.com/PaddlePaddle/Paddle/pull/72559) 导致 `PaddleSeg_vit_adapter_bs4_fp32_DP_N1C1_d2sT` 开启CINN 训练失败，主要原因是导入自定义模块无法正常 fallback，以下是最小复现代码
```python
# 该文件为 import 的内容
# .venv/lib/python3.10/site-packages/ms_deform_attn-0.0.0-py3.10-linux-x86_64.egg/ms_deform_attn.py

    @strict_mode_guard(False)
    def test_import(self):
        def import_func(x):
            try:
                # x += 1
                import ms_deform_attn

                x /= 2
            except:
                # x *= 3
                print(
                    "Import ms_deform_attn failed.test/sot/test_24_exceptions.py"
                )
            return x / 1

        self.assert_results(import_func, paddle.to_tensor(0.5))
```

PCard-66972


Diff:
diff --git a/python/paddle/jit/sot/opcode_translator/executor/exception_stack.py b/python/paddle/jit/sot/opcode_translator/executor/exception_stack.py
index 14c4f866261453..1947521bf48510 100644
--- a/python/paddle/jit/sot/opcode_translator/executor/exception_stack.py
+++ b/python/paddle/jit/sot/opcode_translator/executor/exception_stack.py
@@ -15,18 +15,21 @@
 from __future__ import annotations
 
 import dataclasses
+from typing import TYPE_CHECKING
 
 from ...utils import InnerError
 from .variables import ConstantVariable, ExceptionVariable
 
+if TYPE_CHECKING:
+    from .function_graph import FunctionGraph
+
 
 @dataclasses.dataclass
 class ExceptionStack:
-
     # This data structure manages exceptions as in CPython, primarily handling
     # the __context__ attribute of SotCapturedException.
 
-    _exception_stack: list[ExceptionVariable | None] = dataclasses.field(
+    _exception_stack: list[ExceptionVariable] = dataclasses.field(
         default_factory=list
     )
     _current_exception: ExceptionVariable | None = dataclasses.field(
@@ -36,7 +39,9 @@ class ExceptionStack:
     def clear_current_exception(self):
         self._current_exception = None
 
-    def set_current_exception(self, val: ExceptionVariable, graph):
+    def set_current_exception(
+        self, val: ExceptionVariable, graph: FunctionGraph
+    ):
         self._set_context_and_break_context_reference_cycle(val, graph)
         self._current_exception = val
 
@@ -49,11 +54,18 @@ def get_current_exception(self):
             raise InnerError("Current exception should not be None")
         return self._current_exception
 
-    def _set_context_recursive(self, val: ExceptionVariable, prev_idx):
+    def _set_context_and_break_context_reference_cycle(
+        self, val: ExceptionVariable, graph: FunctionGraph
+    ):
+        # set Exception.__context__
+        self._set_context_recursive(val, len(self._exception_stack) - 1)
+        self._break_context_reference_cycle(val, graph)
+
+    def _set_context_recursive(self, val: ExceptionVariable, prev_idx: int):
         # Recursively sets the __context__ attribute for ExceptionVariable objects
         # in self._exception_stack. Ensures that __context__ is properly linked
         # to the previous exception in the stack.
-        if (ctx := val.__context__) and type(ctx) is not ConstantVariable:
+        if (ctx := val.__context__) and not isinstance(ctx, ConstantVariable):
             return val
         if (
             len(self._exception_stack) + prev_idx > 0
@@ -63,7 +75,9 @@ def _set_context_recursive(self, val: ExceptionVariable, prev_idx):
             val.setattr("__context__", prev)
         return val
 
-    def _break_context_reference_cycle(self, val: ExceptionVariable, graph):
+    def _break_context_reference_cycle(
+        self, val: ExceptionVariable, graph: FunctionGraph
+    ):
         # Detects and breaks cycles in exception __context__ chains using Floyd's algorithm,
         # following CPython's implementation.
 
@@ -71,8 +85,8 @@ def _break_context_reference_cycle(self, val: ExceptionVariable, graph):
         slow_update_toggle = False
         while True:
             context = fast.__context__
-            if (
-                type(context) is ConstantVariable
+            if isinstance(
+                context, ConstantVariable
             ):  # End of the chain; no context set
                 break
 
@@ -92,28 +106,24 @@ def _break_context_reference_cycle(self, val: ExceptionVariable, graph):
                 slow = slow.__context__
             slow_update_toggle = not slow_update_toggle
 
-    def _set_context_and_break_context_reference_cycle(
-        self, val: ExceptionVariable, graph
-    ):
-        # set Exception.__context__
-        self._set_context_recursive(val, len(self._exception_stack) - 1)
-        self._break_context_reference_cycle(val, graph)
-
-    def pop(self):
+    def pop(self) -> ExceptionVariable:
         return self._exception_stack.pop()
 
-    def push(self, val):
+    def push(self, val: ExceptionVariable) -> None:
         self._exception_stack.append(val)
 
+    def empty(self) -> bool:
+        return len(self._exception_stack) == 0
+
     def __len__(self):
         return len(self._exception_stack)
 
-    def __str__(self):
-        return f"{self._exception_stack}"
+    def __repr__(self):
+        return f"ExceptionStack({self._exception_stack})"
 
-    def __getitem__(self, idx):
+    def __getitem__(self, idx: int) -> ExceptionVariable:
         return self._exception_stack[idx]
 
-    def cleanup(self):
+    def cleanup(self) -> None:
         self._exception_stack[:] = []
         self._current_exception = None
diff --git a/python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py b/python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py
index 46a2fbe537c2a6..6d6876aa35b37f 100644
--- a/python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py
+++ b/python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py
@@ -60,6 +60,7 @@
 from ..instruction_utils.opcode_info import (
     NEED_TO_BOOL,
     RETURN,
+    ExceptionHandler,
     JumpDirection,
     PopJumpCond,
 )
@@ -139,10 +140,7 @@
 
 # In Python 3.13, the method layout is changed, and a NULL will be pushed after the value.
 CALL_METHOD_LAYOUT_NULL_AFTER_VALUE = sys.version_info >= (3, 13)
-ALREADY_SUPPORTED_EXCEPTION = sys.version_info >= (
-    3,
-    9,
-) and sys.version_info < (
+ALREADY_SUPPORTED_EXCEPTION = sys.version_info < (
     3,
     11,
 )
@@ -357,7 +355,7 @@ def inner(*args, **kwargs):
 
 def fallback_if_python_version_unsupported(fn: Callable):
     def inner(*args, **kwargs):
-        if sys.version_info >= (3, 11):
+        if not ALREADY_SUPPORTED_EXCEPTION:
             raise FallbackError(
                 "SOT currently only partially supports exception handling (Python 3.10 and below). "
                 "Unsupported exception bytecode will fall back to dynamic graph mode."
@@ -680,20 +678,24 @@ def step(self, instr: Instruction):
 
     def handle_exception(self, e: SotCapturedException):
         # TODO(DrRyanHuang): The newly created ExceptionVariable might differ from the previous one
-        e_var = VariableFactory.from_value(e, self._graph, DummyTracker([]))
+        e_var = VariableFactory.from_value(
+            e,
+            self._graph,
+            DummyTracker(e.tracked_args),
+        )
 
         # The exception is not raised by `raise Exception`
         if (
-            len(self.exception_stack) == 0
+            self.exception_stack.empty()
             or self.exception_stack.get_current_exception() != e_var
         ):
             self.exception_stack.set_current_exception(e_var, self._graph)
 
-        if len(self.vframe.block_stack):
+        if self.vframe.block_stack:
             # The implementation is referenced from the exception_unwind section
             # of CPython's main_loop.
             block_stack_entry = self.vframe.block_stack.pop()
-            while block_stack_entry.inst.opname == "EXCEPT_HANDLER":
+            while block_stack_entry.inst.opname == ExceptionHandler.opname:
                 # Remove previous EXCEPT_HANDLER entries, which indicate that the
                 # exception has already been handled. Continue until a SETUP_FINALLY
                 # block is encountered, which signifies an active exception handler.
@@ -704,7 +706,7 @@ def handle_exception(self, e: SotCapturedException):
                     # frame, so the exception is propagated to the outer function for handling.
                     self.stack.pop_n(
                         len(self.stack)
-                    )  # clear stack to prevent memory leaks
+                    )  # Just like CPython; no memory leaks in our simulation
                     raise e
                 block_stack_entry = self.vframe.block_stack.pop()
 
@@ -719,7 +721,7 @@ def handle_exception(self, e: SotCapturedException):
             # Push a dummy EXCEPT_HANDLER block onto the stack to indicate that exception
             # handling has begun and to record the current stack level.
             EXCEPT_HANDLER_INSTRUCTION = Instruction(
-                257, "EXCEPT_HANDLER", None, 0
+                ExceptionHandler.opcode, ExceptionHandler.opname, None, 0
             )
             self.vframe.block_stack.append(
                 BlockStackItem(
@@ -2067,7 +2069,7 @@ def LOAD_ASSERTION_ERROR(self, instr: Instruction):
     def POP_EXCEPT(self, instr: Instruction):
         assert len(self.vframe.block_stack) > 0
 
-        if self.vframe.block_stack[-1].inst.opname != "EXCEPT_HANDLER":
+        if self.vframe.block_stack[-1].inst.opname != ExceptionHandler.opname:
             raise FallbackError(
                 "Bug in SOT tracing of exception handling."
                 "Top of the block stack is not EXCEPT_HANDLER."
@@ -2076,7 +2078,7 @@ def POP_EXCEPT(self, instr: Instruction):
         self.vframe.block_stack.pop()
         self.stack.pop_n(3)
 
-        assert len(self.exception_stack)
+        assert self.exception_stack
         self.exception_stack.pop()
 
     @staticmethod
@@ -2107,7 +2109,7 @@ def _raise_exception_instance(
     @fallback_if_python_version_unsupported
     def RAISE_VARARGS(self, instr: Instruction):
         if instr.arg == 0:
-            if not len(self.exception_stack):
+            if self.exception_stack.empty():
                 msg = ConstantVariable.wrap_literal(
                     "No active exception to reraise", self._graph
                 )
@@ -2164,7 +2166,7 @@ def raise_sot_captured_exception(
             exc_type, self._graph, DummyTracker(list(args))
         ).call_function(*args, **kwargs)
         self.exception_stack.set_current_exception(exc, self._graph)
-        raise SotCapturedExceptionFactory.get(exc_type)
+        raise SotCapturedExceptionFactory.create(exc.get_py_value())
 
 
 class OpcodeExecutor(OpcodeExecutorBase):
@@ -2323,13 +2325,13 @@ def get_compute_fn_and_update_changed_vars(
                 compile_graph_result, store_vars, store_var_info
             )
 
-    def fallback_when_block_stack_is_empty(self):
+    def fallback_when_block_stack_is_not_empty(self):
         """
         SOT currently doesn't support a non-empty block stack (related to exception handling),
         triggering a fallback.
         """
 
-        if len(self.vframe.block_stack):
+        if self.vframe.block_stack:
             raise FallbackError(
                 'SOT currently does not support a non-empty block stack, '
                 'triggering a fallback\n'
@@ -2345,7 +2347,7 @@ def _break_graph_when_if(self, result: TensorVariable, instr: Instruction):
             instr: The jump instruction.
 
         """
-        self.fallback_when_block_stack_is_empty()
+        self.fallback_when_block_stack_is_not_empty()
         self._graph.add_global_guarded_variable(result)
 
         # 1. analyse info
@@ -2505,6 +2507,7 @@ def _break_graph_when_call(
             push_n: The number of elements to be pushed onto the stack.
 
         """
+        self.fallback_when_block_stack_is_not_empty()
         self.stack = origin_stack
 
         # 1. collect infomations
@@ -2606,6 +2609,7 @@ def create_resume_fn(null_indices):
     def _break_graph_when_for_loop(
         self, iterator: VariableBase, for_iter: Instruction
     ):
+        self.fallback_when_block_stack_is_not_empty()
         # 1. find the range of loop body
         assert for_iter.jump_to is not None
         for_iter_idx = self.indexof(for_iter)
diff --git a/python/paddle/jit/sot/opcode_translator/executor/variable_dispatch.py b/python/paddle/jit/sot/opcode_translator/executor/variable_dispatch.py
index 2b2f92a152c7b5..cb623141dc3daa 100644
--- a/python/paddle/jit/sot/opcode_translator/executor/variable_dispatch.py
+++ b/python/paddle/jit/sot/opcode_translator/executor/variable_dispatch.py
@@ -631,12 +631,12 @@ def dispatch_list_ne(lhs: ListVariable, rhs: ListVariable):
 )
 
 
-def register_exception(exc):
-    @Dispatcher.register_decorator(exc)
+def register_exception(exc_type: type[Exception]):
+    @Dispatcher.register_decorator(exc_type)
     def builtin_exception_dispatcher(*args) -> int:
+        exc = exc_type(*args)
         return ExceptionVariable(
             exc,
-            *args,
             graph=Dispatcher.graph,
             tracker=DummyTracker([]),
         )
@@ -1524,7 +1524,7 @@ def numpy_binary_dispatcher(var: NumPyVariable, other: NumPyVariable):
 
 
 # `operator.eq` of `ExceptionVariable` dispatch
-def exception_variable_equal(left, right):
+def exception_variable_equal(left: ExceptionVariable, right: ExceptionVariable):
     result = (left is right) or (left.get_py_value() == right.get_py_value())
     return VariableFactory.from_value(
         result,
@@ -1623,10 +1623,11 @@ def dispatch_all(var: ContainerVariable | IterVariable):
 Dispatcher.register(
     operator_exception_match,
     ("BuiltinVariable | ExceptionVariable", "BuiltinVariable | TupleVariable"),
-    lambda exc_instance, expected_exc_types: ConstantVariable.wrap_literal(
+    lambda exc_instance, expected_exc_types: ConstantVariable(
         ExceptionVariable.check_if_exception_matches(
             exc_instance, expected_exc_types
         ),
         exc_instance.graph,
+        DummyTracker([exc_instance, expected_exc_types]),
     ),
 )
diff --git a/python/paddle/jit/sot/opcode_translator/executor/variables/basic.py b/python/paddle/jit/sot/opcode_translator/executor/variables/basic.py
index f5ae4b231b4a20..69b48feaf2927c 100644
--- a/python/paddle/jit/sot/opcode_translator/executor/variables/basic.py
+++ b/python/paddle/jit/sot/opcode_translator/executor/variables/basic.py
@@ -2158,50 +2158,35 @@ class ExceptionVariable(VariableBase):
 
     def __init__(
         self,
-        exc: Exception | type[Exception],
-        *args,
+        exc: Exception,
         graph: FunctionGraph = None,
         tracker: Tracker = None,
     ) -> None:
         super().__init__(graph=graph, tracker=tracker)
 
-        self.record_exception = False
-        if isinstance(exc, Exception):
-            exc_type = exc.__class__
-            self.record_exception = True
-
-        elif isinstance(exc, type) and issubclass(exc, Exception):
-            exc_type = exc
-
-        else:
-            # TODO(DrRyanHuang): Should `exc_type` be a `BuiltinVariable`?
-            raise InnerError(
-                f"ExceptionVariable parameter `exc` should be an Exception class or instance, but got `{type(exc)}`:`{exc}`"
-            )
-        py_args = []
-        for arg in args:
-            # TODO(DrRyanHuang): Should `args` be a tuple containing exclusively `VariableBase`?
-            if not isinstance(arg, VariableBase):
-                raise InnerError(
-                    f"ExceptionVariable parameter `args` be a tuple containing exclusively `VariableBase`, but got `{type(arg)}`:`{arg}`"
-                )
-            py_args.append(arg.get_py_value())
-
-        self.exc = exc if self.record_exception else exc(*py_args)
-        self.exc_type = exc_type
-        self.args = args
+        self.exc = exc
+        self.exc_type = exc.__class__
+        self.args_variables = VariableFactory.from_value(
+            exc.args, graph=graph, tracker=GetAttrTracker(self, "args")
+        )
 
         self.__context__ = VariableFactory.from_value(
-            self.exc.__context__, graph=graph, tracker=tracker
+            self.exc.__context__,
+            graph=graph,
+            tracker=GetAttrTracker(self, "__context__"),
         )
 
         # raise ... from ...
         self.__cause__ = VariableFactory.from_value(
-            self.exc.__cause__, graph=graph, tracker=tracker
+            self.exc.__cause__,
+            graph=graph,
+            tracker=GetAttrTracker(self, "__cause__"),
         )
 
         self.__suppress_context__ = VariableFactory.from_value(
-            self.exc.__suppress_context__, graph=graph, tracker=tracker
+            self.exc.__suppress_context__,
+            graph=graph,
+            tracker=GetAttrTracker(self, "__suppress_context__"),
         )
 
         # NOTE: Currently, since our primary goal is to trace the network structure of variables,
@@ -2214,28 +2199,12 @@ def get_py_type(self):
         return self.exc_type
 
     def get_py_value(self):
-        if self.record_exception:
-            exception = self.exc
-        else:
-            exception = self.exc_type(
-                *[arg.get_py_value() for arg in self.args]
-            )
-
-            exception.__context__ = (
-                exception.__context__ or self.__context__.get_py_value()
-            )
-            exception.__cause__ = (
-                exception.__cause__ or self.__cause__.get_py_value()
-            )
-            exception.__suppress_context__ = exception.__suppress_context__ or (
-                self.__suppress_context__.get_py_value()
-            )
-        return exception
+        return self.exc
 
     @property
     def main_info(self) -> dict[str, Any]:
         return {
-            "exception_cls": self.exc_type,
+            "exception": self.exc,
         }
 
     def setattr(self, key: str, value):
@@ -2247,7 +2216,7 @@ def setattr(self, key: str, value):
                 and value.get_py_value() is None
             ) or isinstance(
                 value,
-                (ExceptionVariable),
+                ExceptionVariable,
             ):
                 self.__context__ = value
             else:
@@ -2260,7 +2229,7 @@ def setattr(self, key: str, value):
                 and value.get_py_value() is None
             ) or isinstance(
                 value,
-                (ExceptionVariable),
+                ExceptionVariable,
             ):
                 self.__cause__ = value
                 self.__suppress_context__ = ConstantVariable.wrap_literal(
@@ -2271,9 +2240,8 @@ def setattr(self, key: str, value):
                     "exception cause must be None or derive from BaseException"
                 )
         elif key == "__suppress_context__":
-            if isinstance(value, ConstantVariable) and value.get_py_value() in (
-                True,
-                False,
+            if isinstance(value, ConstantVariable) and isinstance(
+                value.get_py_value(), bool
             ):
                 self.__suppress_context__ = value
             else:
@@ -2296,20 +2264,10 @@ def getattr(self, name: str, default=None) -> VariableBase:
             return ConstantVariable.wrap_literal(None, self.graph)
 
         if name == "args":
-            from .container import ListVariable
-
-            return ListVariable(
-                self.args, self.graph, GetAttrTracker(self, "args")
-            )
+            return self.args_variables
 
         return super().getattr(name, default)
 
-    def __str__(self):
-        return f"{self.__class__.__name__}({self.exc_type})"
-
-    def __repr__(self):
-        return self.__str__()
-
     @classmethod
     def check_if_exception_matches(
         cls,
@@ -2351,49 +2309,8 @@ def check_if_exception_matches(
     @VariableFactory.register_from_value()
     def from_value(value: Exception, graph: FunctionGraph, tracker: Tracker):
         if isinstance(value, Exception):
-            args = [
-                ConstantVariable.wrap_literal(arg, graph) for arg in value.args
-            ]
             exception_var = ExceptionVariable(
-                value.__class__, *args, graph=graph, tracker=tracker
+                value, graph=graph, tracker=tracker
             )
-            if value.__context__ is not None:
-                exception_var.setattr(
-                    "__context__",
-                    VariableFactory.from_value(
-                        value.__context__, graph=graph, tracker=tracker
-                    ),
-                )
-            if value.__cause__ is not None:
-                exception_var.setattr(
-                    "__cause__",
-                    VariableFactory.from_value(
-                        value.__cause__, graph=graph, tracker=tracker
-                    ),
-                )
-            exception_var.setattr(
-                "__suppress_context__",
-                ConstantVariable.wrap_literal(
-                    value.__suppress_context__, graph
-                ),
-            )
-
             return exception_var
         return None
-
-    # def __eq__(self, other: ExceptionVariable) -> bool:
-    #     if sys.version_info >= (3, 8) and sys.version_info < (3, 9):
-    #         raise FallbackError("Python version >= 3.8 but < 3.9")
-
-    #     # `operator.eq` of `ExceptionVariable` dispatch
-    #     def exception_variable_equal(left, right):
-    #         result = (left is right) or (
-    #             left.get_py_value() == right.get_py_value()
-    #         )
-    #         return VariableFactory.from_value(
-    #             result,
-    #             left.graph,
-    #             tracker=DummyTracker([left, right]),
-    #         )
-
-    #     return exception_variable_equal(self, other)
diff --git a/python/paddle/jit/sot/opcode_translator/executor/variables/callable.py b/python/paddle/jit/sot/opcode_translator/executor/variables/callable.py
index 652453d3b4408b..861721eb8bd4ab 100644
--- a/python/paddle/jit/sot/opcode_translator/executor/variables/callable.py
+++ b/python/paddle/jit/sot/opcode_translator/executor/variables/callable.py
@@ -876,7 +876,9 @@ def call_function(self, /, *args, **kwargs):
                 # so we can directly raise SotErrorBase.
                 raise
             except Exception as e:
-                raise SotCapturedExceptionFactory.create(origin_exc=e) from e
+                raise SotCapturedExceptionFactory.create(
+                    origin_exc=e, tracked_args=[args, kwargs]
+                ) from e
 
         if ENV_SOT_ALLOW_DYNAMIC_SHAPE.get() and any(
             isinstance(var, SymbolicVariable)
diff --git a/python/paddle/jit/sot/opcode_translator/instruction_utils/opcode_info.py b/python/paddle/jit/sot/opcode_translator/instruction_utils/opcode_info.py
index 29ff82963fddbf..04f5916cb34e3d 100644
--- a/python/paddle/jit/sot/opcode_translator/instruction_utils/opcode_info.py
+++ b/python/paddle/jit/sot/opcode_translator/instruction_utils/opcode_info.py
@@ -112,3 +112,8 @@ def _get_pyopcode_cache_size() -> dict[str, int]:
 
 
 PYOPCODE_CACHE_SIZE = _get_pyopcode_cache_size()
+
+
+class ExceptionHandler:
+    opcode = 257
+    opname = "EXCEPT_HANDLER"
diff --git a/python/paddle/jit/sot/opcode_translator/skip_files.py b/python/paddle/jit/sot/opcode_translator/skip_files.py
index bf84a4c32c5acf..e91c5b9f79367b 100644
--- a/python/paddle/jit/sot/opcode_translator/skip_files.py
+++ b/python/paddle/jit/sot/opcode_translator/skip_files.py
@@ -23,6 +23,7 @@
 import dataclasses
 import enum
 import functools
+import genericpath
 import importlib
 import inspect
 import linecache
@@ -92,6 +93,7 @@
     uuid,
     setuptools,
     warnings,
+    genericpath,
 }
 
 if sys.version_info < (3, 11):
diff --git a/python/paddle/jit/sot/utils/exceptions.py b/python/paddle/jit/sot/utils/exceptions.py
index 3963766fdfc910..4b9b54a6e38948 100644
--- a/python/paddle/jit/sot/utils/exceptions.py
+++ b/python/paddle/jit/sot/utils/exceptions.py
@@ -19,7 +19,7 @@
 from .info_collector import BreakGraphReasonInfo
 
 if TYPE_CHECKING:
-    from collections import Any
+    from ..opcode_translator.executor.variables.base import VariableBase
 
 
 class BreakGraphReasonBase:
@@ -379,7 +379,6 @@ class SotCapturedStopIteration(SotCapturedOSError): ...
 
 
 class SotCapturedExceptionFactory:
-
     # This dictionary maps common built-in Python Exception types to their corresponding SotCapturedException
     # types, preserving the original exception hierarchy for proper inheritance behavior.
     # Reference: https://docs.python.org/3/library/exceptions.html#exception-hierarchy
@@ -416,7 +415,6 @@ def get(
         cls,
         exc_type: type[Exception],
     ) -> type[SotCapturedException]:
-
         if isinstance(exc_type, type) and issubclass(
             exc_type, SotCapturedException
         ):
@@ -432,30 +430,22 @@ def get(
     @classmethod
     def create(
         cls,
-        origin_exc: Exception | None = None,
-        exc_type: type[Exception] | None = None,
-        args: list[Any] | tuple[Any] | None = None,
-        context: Exception | None = None,
-        cause: Exception | None = None,
-        suppress_context: bool | None = None,
-        traceback: None = None,
+        origin_exc: Exception,
+        tracked_args: list[VariableBase] | None = None,
     ) -> SotCapturedException:
         # transform an Exception to SotCapturedException
-        args = args or []
-
-        if origin_exc is not None:
-            exc_type = origin_exc.__class__
-            args = origin_exc.args
-            context = origin_exc.__context__
-            cause = origin_exc.__cause__
-            suppress_context = origin_exc.__suppress_context__
-            traceback = origin_exc.__traceback__
+        exc_type = origin_exc.__class__
 
         new_exc_type = cls.get(exc_type)
-        new_exc = new_exc_type(*args)
-        new_exc.__cause__ = cause
-        new_exc.__context__ = context
-        new_exc.__suppress_context__ = suppress_context
-        new_exc.__traceback__ = traceback
+        new_exc = new_exc_type(*origin_exc.args)
+        new_exc.__cause__ = origin_exc.__cause__
+        new_exc.__context__ = origin_exc.__context__
+        new_exc.__suppress_context__ = origin_exc.__suppress_context__
+        new_exc.__traceback__ = origin_exc.__traceback__
+
+        # Propagating Exception Parameters through SotCapturedException
+        if tracked_args is None:
+            tracked_args = []
+        new_exc.tracked_args = tracked_args
 
         return new_exc
diff --git a/test/sot/test_24_exceptions.py b/test/sot/test_24_exceptions.py
index 7da81cc1b58a32..42647978c65ffa 100644
--- a/test/sot/test_24_exceptions.py
+++ b/test/sot/test_24_exceptions.py
@@ -11,7 +11,6 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-import sys
 import unittest
 
 from test_case_base import (
@@ -19,10 +18,731 @@
 )
 
 import paddle
+from paddle.jit.sot import symbolic_translate
+from paddle.jit.sot.opcode_translator.executor.opcode_executor import (
+    ALREADY_SUPPORTED_EXCEPTION,
+)
 from paddle.jit.sot.psdb import check_no_breakgraph
 from paddle.jit.sot.utils import strict_mode_guard
 
-NOT_ALLOW_FALLBACK = sys.version_info < (3, 11) and sys.version_info >= (3, 9)
+NOT_ALLOW_FALLBACK = ALREADY_SUPPORTED_EXCEPTION
+
+
+class TestRaiseVarargs(TestCaseBase):
+    # test `RAISE_VARARGS`
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_0_wo_exception(x):
+        try:
+            x += 1
+            # In CPython, `RuntimeError` will be triggered at this point.
+            # SOT have setup the exception stack and raise the exception manually.
+            # This function is designed to test scenarios involving only the `raise` statement.
+            raise  # Bare `raise` statement is not inside an exception handler # noqa: PLE0704
+            x /= 2
+        except RuntimeError:
+            x -= 3
+        x *= 4
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_0_zero_div_err(x):
+        x += 1
+        try:
+            try:
+                x += 2
+                result = 10 / 0
+            except ZeroDivisionError:
+                x += 3
+                raise  # RAISE_VARARGS(0)
+        except:
+            x += 4
+        return x + 5
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_0_simulating_zero_div_err(x):
+        x += 1
+        try:
+            try:
+                x += 2
+                raise ZeroDivisionError("")
+            except ZeroDivisionError:
+                x += 3
+                raise  # RAISE_VARARGS(0)
+        except:
+            x += 4
+        return x + 5
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_1(x):
+        x += 1
+        try:
+            try:
+                x += 2
+            except:
+                x += 3
+            else:
+                x += 4
+                raise NotImplementedError  # RAISE_VARARGS(1)
+                x += 5
+        except:
+            x += 6
+        return x + 7
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_2(x):
+        x -= 10
+        try:
+            try:
+                x -= 300
+            finally:
+                x -= 400
+                raise ValueError from None  # RAISE_VARARGS(2)
+        except ValueError:
+            x -= 500
+
+        return x - 600
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_1_2(x):
+        try:
+            x += 1
+            try:
+                x /= 2
+                raise NameError  # RAISE_VARARGS(1)
+                x *= 3
+            except NameError as e:
+                x -= 4
+                raise TimeoutError("TESTING") from e  # RAISE_VARARGS(2)
+        except:
+            x /= 5
+        return x + 6
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_1_0(x):
+        try:
+            try:
+                x -= 1
+                raise ValueError("TESTING")  # RAISE_VARARGS(1)
+                x += 2
+            except NotImplementedError:
+                x /= 3
+                raise  # RAISE_VARARGS(0)
+        except (KeyError, IndexError):
+            x *= 4
+        except ValueError:
+            x += 5
+        return x
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_RAISE_VARARGS_argc(self):
+        self.assert_results(
+            self.argc_equal_to_0_wo_exception, paddle.to_tensor(0.01)
+        )
+        self.assert_results(
+            self.argc_equal_to_0_zero_div_err, paddle.to_tensor(0.02)
+        )
+        self.assert_results(
+            self.argc_equal_to_0_simulating_zero_div_err, paddle.to_tensor(0.03)
+        )
+        self.assert_results(self.argc_equal_to_1, paddle.to_tensor(0.04))
+        self.assert_results(self.argc_equal_to_2, paddle.to_tensor(0.05))
+        self.assert_results(self.argc_equal_to_1_2, paddle.to_tensor(0.06))
+        self.assert_results(self.argc_equal_to_1_0, paddle.to_tensor(0.07))
+
+
+class TestException(TestCaseBase):
+    @staticmethod
+    def create_builtin_exception(x):
+        def identity(e):
+            return e
+
+        x += 1
+        value_error = ValueError()
+        identity(value_error)
+        x += 2
+        type_error = TypeError("")
+        identity(type_error)
+        x += 3
+        key_error = KeyError("")
+        identity(key_error)
+        x += 4
+        exception = Exception("")
+        identity(exception)
+        x += 5
+        unicode_translate_error = UnicodeTranslateError("", -1, -1, "")
+        identity(unicode_translate_error)
+        x += 6
+        return x
+
+    @staticmethod
+    def create_user_defined_exception(x):
+        # TODO: Need to support user-defined exception
+        return x
+
+    @check_no_breakgraph
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_dispatch(self):
+        self.assert_results(
+            self.create_builtin_exception, paddle.to_tensor(111.0)
+        )
+        self.assert_results(
+            self.create_user_defined_exception, paddle.to_tensor(222.0)
+        )
+
+
+class TestTryExcept(TestCaseBase):
+    # try ... except ...
+    # ---------------- test raising exception directly ----------------
+    @staticmethod
+    def raise_value_error_obj():
+        raise ValueError("Test whether raising `ValueError`")
+
+    @staticmethod
+    def raise_value_error_cls():
+        raise ValueError
+
+    @staticmethod
+    def raise_asserterror(x):
+        assert x, "Test AssertionError"
+
+    # Since the exceptions are not handled, fallback is permitted.
+    @strict_mode_guard(False)
+    def test_exception_raising(self):
+        with self.assertRaisesRegex(
+            ValueError, "Test whether raising `ValueError`"
+        ):
+            symbolic_translate(self.raise_value_error_obj)()
+
+        with self.assertRaisesRegex(ValueError, ""):
+            symbolic_translate(self.raise_value_error_cls)()
+
+        with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
+            symbolic_translate(self.raise_asserterror)(False)
+
+        with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
+            symbolic_translate(self.raise_asserterror)(paddle.to_tensor(0))
+
+    # ---------------- without error ----------------
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_wo_error(x):
+        try:
+            x = x + 1
+        except:
+            x = x * 2
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_wo_error(x):
+        try:
+            x = x + 1
+        except Exception:
+            x = x * 2
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_wo_error(x):
+        try:
+            x = x + 1
+        except Exception as e:
+            x = x * 2
+        return x
+
+    # ---------------- with error ----------------
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_with_error_obj(x):
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError(f"{__class__.__name__}")
+            x = x * 3
+        except:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_with_error_cls(x):
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError
+            x = x * 3
+        except:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_with_error(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        x = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except Exception:
+            x = x * 2
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_error(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except ValueError as e:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_error_tuple(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except (ValueError, KeyError, NotImplementedError) as e:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_unmatched_error(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except KeyError as e:
+            y = x * 2
+        return y + 3
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_matched_error_reraise(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise IndexError("TESTING!")
+            x = x * 3
+        except IndexError as e:
+            y = x * 2
+            raise LookupError("TESTING!")
+        return y + 3
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_try_except(self):
+        self.assert_results(self.try_except_wo_error, paddle.to_tensor(2))
+        self.assert_results(
+            self.try_except_exception_wo_error, paddle.to_tensor(3)
+        )
+        self.assert_results(
+            self.try_except_exception_as_e_wo_error, paddle.to_tensor(4)
+        )
+        self.assert_results(self.try_except_with_error_obj, paddle.to_tensor(5))
+        self.assert_results(self.try_except_with_error_cls, paddle.to_tensor(6))
+        self.assert_results(
+            self.try_except_exception_with_error, paddle.to_tensor(7)
+        )
+        self.assert_results(
+            self.try_except_exception_as_e_with_error, paddle.to_tensor(8)
+        )
+        self.assert_results(
+            self.try_except_exception_as_e_with_error_tuple, paddle.to_tensor(9)
+        )
+
+    @strict_mode_guard(False)
+    def test_error(self):
+        # RERAISE
+        self.assert_exceptions(
+            ValueError,
+            "TESTING!",
+            self.try_except_exception_as_e_with_unmatched_error,
+            paddle.to_tensor(0.001),
+        )
+
+        self.assert_exceptions(
+            LookupError,
+            "TESTING!",
+            self.try_except_exception_as_e_with_matched_error_reraise,
+            paddle.to_tensor(0.001),
+        )
+
+
+class TestTryFinally(TestCaseBase):
+    # try ... finally ...
+    # ---------------- without error ----------------
+    @staticmethod
+    @check_no_breakgraph
+    def try_finally_wo_error(x):
+        try:
+            x = 1 + x
+        finally:
+            x *= 2
+        return x
+
+    # ---------------- with error ----------------
+    @staticmethod
+    @check_no_breakgraph
+    def try_finally_with_error_but_return_in_finally(x):
+        # RERAISE
+        try:
+            x = 3 + x
+            raise NotImplementedError("TESTING!")
+            x = 300 + x
+        finally:
+            x *= 2
+            # `return` inside `finally` blocks cause exceptions to be silenced
+            return x  # noqa: B012
+
+    @staticmethod
+    def try_finally_with_error(x):
+        # RERAISE
+        try:
+            x = 3 + x
+            raise NotImplementedError("TESTING!")
+            x = 300 + x
+        finally:
+            x *= 2
+        return x
+
+    @staticmethod
+    def try_finally_with_error_in_finally(x):
+        # RERAISE
+        try:
+            x = 3 + x
+            return x
+        finally:
+            x *= 2
+            raise TimeoutError("TESTING!")
+            x = 300 + x
+        return x
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_try_finally(self):
+        self.assert_results(self.try_finally_wo_error, paddle.to_tensor(14))
+        self.assert_results(
+            self.try_finally_with_error_but_return_in_finally,
+            paddle.to_tensor(15),
+        )
+
+    @strict_mode_guard(False)
+    def test_error(self):
+        # RERAISE
+        self.assert_exceptions(
+            NotImplementedError,
+            "TESTING!",
+            self.try_finally_with_error,
+            paddle.to_tensor(16),
+        )
+        self.assert_exceptions(
+            TimeoutError,
+            "TESTING!",
+            self.try_finally_with_error_in_finally,
+            paddle.to_tensor(17),
+        )
+
+
+class TestTryExceptElse(TestCaseBase):
+    # try ... except ... else
+    # `else` is useful for code that must be executed if the try clause does not raise an exception.
+
+    # ---------------- without error ----------------
+    @staticmethod
+    def try_except_else(x):
+        try:
+            x += 1
+        except:
+            x += 2
+        else:
+            x += 3
+        return x
+
+    # ---------------- with error ----------------
+    @staticmethod
+    def try_except_else_except_with_matched_error(x):
+        try:
+            x += 4
+            raise ValueError
+        except ValueError:
+            x += 5
+        else:
+            x += 6
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_else_except_with_mismatched_error(x):
+        try:
+            x += 4
+            raise TimeoutError
+        except KeyError:
+            x += 5
+        else:
+            x += 6
+        return x
+
+    @staticmethod
+    def try_except_else_error_in_except(x):
+        try:
+            x += 4
+        except KeyError:
+            x += 5
+            raise ValueError
+        else:
+            x += 6
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_else_error_in_else(x):
+        try:
+            x += 4
+        except KeyError:
+            x += 5
+        else:
+            x += 6
+            raise ValueError("Testing!")
+        return x
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_try_except_else(self):
+        # self.assert_results(self.try_except_else, paddle.to_tensor(14))
+        self.assert_results(
+            self.try_except_else_except_with_matched_error, paddle.to_tensor(15)
+        )
+        # self.assert_results(
+        #     self.try_except_else_error_in_except, paddle.to_tensor(16)
+        # )
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_error(self):
+        # RERAISE
+        self.assert_exceptions(
+            TimeoutError,
+            "",
+            self.try_except_else_except_with_mismatched_error,
+            paddle.to_tensor(0.001),
+        )
+        self.assert_exceptions(
+            ValueError,
+            "Testing!",
+            self.try_except_else_error_in_else,
+            paddle.to_tensor(0.002),
+        )
+
+
+class TestTryExceptFinally(TestCaseBase):
+    # try ... except ... finally
+    # ---------------- without error ----------------
+    @staticmethod
+    def try_except_finally(x):
+        try:
+            x -= 1
+        except:
+            x -= 2
+        finally:
+            x -= 3
+        return x
+
+    # ---------------- without error ----------------
+    @staticmethod
+    def try_except_finally_with_matched_exception(x):
+        try:
+            x -= 1
+            raise ValueError
+        except:
+            x -= 2
+        finally:
+            x -= 3
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_finally_with_mismatched_exception(x):
+        try:
+            x -= 1
+            raise ValueError("TESTING")
+        except AttributeError:
+            x -= 2
+        finally:
+            x -= 3
+        return x
+
+    @staticmethod
+    def try_except_finally_in_except(x):
+        try:
+            x -= 1
+        except AttributeError:
+            x -= 2
+            raise ValueError
+        finally:
+            x -= 3
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_finally_in_finally(x):
+        try:
+            x -= 1
+        except AttributeError:
+            x -= 2
+        finally:
+            x -= 3
+            raise ValueError
+        return x
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_try_except_finally(self):
+        self.assert_results(self.try_except_finally, paddle.to_tensor([0.11]))
+        self.assert_results(
+            self.try_except_finally_with_matched_exception,
+            paddle.to_tensor([0.22]),
+        )
+        self.assert_results(
+            self.try_except_finally_in_except,
+            paddle.to_tensor([0.33]),
+        )
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_error(self):
+        # RERAISE
+        self.assert_exceptions(
+            ValueError,
+            "TESTING",
+            self.try_except_finally_with_mismatched_exception,
+            paddle.to_tensor(0.001),
+        )
+
+        self.assert_exceptions(
+            ValueError,
+            "",
+            self.try_except_finally_in_finally,
+            paddle.to_tensor(0.001),
+        )
+
+
+class TestTryExceptElseFinally(TestCaseBase):
+    # try ... except ... else ... finally
+    # ---------------- without error ----------------
+    @staticmethod
+    def try_except_else_finally(x):
+        try:
+            x -= 1
+        except:
+            x -= 2
+        else:
+            x -= 3
+        finally:
+            x -= 4
+        return x
+
+    # ---------------- with error ----------------
+    @staticmethod
+    def try_except_else_finally_with_matched_exception(x):
+        try:
+            x -= 1
+            raise ValueError
+        except ValueError:
+            x -= 2
+        else:
+            x -= 3
+        finally:
+            x -= 4
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_else_finally_with_mismatched_exception(x):
+        try:
+            x -= 1
+            raise SystemError("TESTING")
+        except NotImplementedError:
+            x -= 2
+        else:
+            x -= 3
+        finally:
+            x -= 4
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_else_finally_with_exception_in_else(x):
+        try:
+            x -= 1
+        except NotImplementedError:
+            x -= 2
+        else:
+            x -= 3
+            raise ModuleNotFoundError("TESTING")
+        finally:
+            x -= 4
+        return x
+
+    @staticmethod
+    @strict_mode_guard(False)
+    def try_except_else_finally_with_exception_in_finally(x):
+        try:
+            x -= 1
+        except NotImplementedError:
+            x -= 2
+        else:
+            x -= 3
+        finally:
+            x -= 4
+            raise SyntaxError("TESTING")
+        return x
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_try_except_finally(self):
+        self.assert_results(
+            self.try_except_else_finally, paddle.to_tensor([0.11])
+        )
+        self.assert_results(
+            self.try_except_else_finally_with_matched_exception,
+            paddle.to_tensor([0.22]),
+        )
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_error(self):
+        # RERAISE
+        self.assert_exceptions(
+            SystemError,
+            "TESTING",
+            self.try_except_else_finally_with_mismatched_exception,
+            paddle.to_tensor(0.001),
+        )
+        self.assert_exceptions(
+            ModuleNotFoundError,
+            "TESTING",
+            self.try_except_else_finally_with_exception_in_else,
+            paddle.to_tensor(0.001),
+        )
+        self.assert_exceptions(
+            SyntaxError,
+            "TESTING",
+            self.try_except_else_finally_with_exception_in_finally,
+            paddle.to_tensor(0.001),
+        )
 
 
 class TestNestingCase(TestCaseBase):
@@ -209,5 +929,20 @@ def try_assert_except(x):
         self.assert_results(try_assert_except, paddle.to_tensor(10))
 
 
+class TestGuard(TestCaseBase):
+    @strict_mode_guard(False)
+    @check_no_breakgraph
+    def test_guard_run(self):
+        def fn():
+            try:
+                paddle.jit.sot.psdb.breakgraph()
+                raise ValueError
+            except ValueError:
+                return True
+            return False
+
+        self.assert_results(fn)
+
+
 if __name__ == "__main__":
     unittest.main()


Reviews:
user: login: SigureMo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T07:50:43Z
user: login: DrRyanHuang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T08:05:43Z
user: login: SigureMo
body: 除去之前说的问题，整体 ok
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T15:45:59Z
user: login: SigureMo
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T13:08:21Z
user: login: SigureMo
body: LGTMeow <img src="https://www.gstatic.com/android/keyboard/emojikitchen/20231113/u1f4ae/u1f4ae_u1f43e.png" width="14" alt="🐾"/>
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-23T02:45:40Z

Review comments:
diff_hunk: @@ -15,14 +15,17 @@
 from __future__ import annotations
 
 import dataclasses
+from typing import TYPE_CHECKING
 
 from ...utils import InnerError
 from .variables import ConstantVariable, ExceptionVariable
 
+if TYPE_CHECKING:
+    from .function_graph import FunctionGraph
+
 
 @dataclasses.dataclass
 class ExceptionStack:
-
     # This data structure manages exceptions as in CPython, primarily handling
     # the __context__ attribute of SotCapturedException.
 
path: python/paddle/jit/sot/opcode_translator/executor/exception_stack.py
user: login: SigureMo
body: 这里的 `_exception_stack` 再确认下会不会有 `None`？
created_at: 2025-05-19T07:43:26Z
author_association: MEMBER
diff_hunk: @@ -2352,7 +2351,8 @@ def check_if_exception_matches(
     def from_value(value: Exception, graph: FunctionGraph, tracker: Tracker):
         if isinstance(value, Exception):
             args = [
-                ConstantVariable.wrap_literal(arg, graph) for arg in value.args
+                VariableFactory.from_value(arg, graph, tracker)
path: python/paddle/jit/sot/opcode_translator/executor/variables/basic.py
user: login: SigureMo
body: tracker 不对吧？

args 没必要分别 create，一次性喂给 `VariableFactory.from_value` 就行

tracker 可以先设置 `DanglingTracker` 然后设置 `GetAttrTracker(exception_var, "args")`
created_at: 2025-05-19T07:46:25Z
author_association: MEMBER
diff_hunk: @@ -2352,7 +2351,8 @@ def check_if_exception_matches(
     def from_value(value: Exception, graph: FunctionGraph, tracker: Tracker):
         if isinstance(value, Exception):
             args = [
-                ConstantVariable.wrap_literal(arg, graph) for arg in value.args
+                VariableFactory.from_value(arg, graph, tracker)
path: python/paddle/jit/sot/opcode_translator/executor/variables/basic.py
user: login: SigureMo
body: 另外 `__init__` 是在下个 PR 修改么？
created_at: 2025-05-19T07:48:56Z
author_association: MEMBER
diff_hunk: @@ -15,14 +15,17 @@
 from __future__ import annotations
 
 import dataclasses
+from typing import TYPE_CHECKING
 
 from ...utils import InnerError
 from .variables import ConstantVariable, ExceptionVariable
 
+if TYPE_CHECKING:
+    from .function_graph import FunctionGraph
+
 
 @dataclasses.dataclass
 class ExceptionStack:
-
     # This data structure manages exceptions as in CPython, primarily handling
     # the __context__ attribute of SotCapturedException.
 
path: python/paddle/jit/sot/opcode_translator/executor/exception_stack.py
user: login: DrRyanHuang
body: 移除了，不会有 None
created_at: 2025-05-20T08:05:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -11,18 +11,739 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-import sys
 import unittest
 
 from test_case_base import (
     TestCaseBase,
 )
 
 import paddle
+from paddle.jit.sot import symbolic_translate
+from paddle.jit.sot.opcode_translator.executor.opcode_executor import (
+    ALREADY_SUPPORTED_EXCEPTION,
+)
 from paddle.jit.sot.psdb import check_no_breakgraph
 from paddle.jit.sot.utils import strict_mode_guard
 
-NOT_ALLOW_FALLBACK = sys.version_info < (3, 11) and sys.version_info >= (3, 9)
+NOT_ALLOW_FALLBACK = ALREADY_SUPPORTED_EXCEPTION
+
+
+class TestRaiseVarargs(TestCaseBase):
+    # test `RAISE_VARARGS`
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_0_wo_exception(x):
+        try:
+            x += 1
+            # In CPython, `RuntimeError` will be triggered at this point.
+            # SOT have setup the exception stack and raise the exception manually.
+            # This function is designed to test scenarios involving only the `raise` statement.
+            raise  # Bare `raise` statement is not inside an exception handler # noqa: PLE0704
+            x /= 2
+        except RuntimeError:
+            x -= 3
+        x *= 4
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_0_zero_div_err(x):
+        x += 1
+        try:
+            try:
+                x += 2
+                result = 10 / 0
+            except ZeroDivisionError:
+                x += 3
+                raise  # RAISE_VARARGS(0)
+        except:
+            x += 4
+        return x + 5
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_0_simulating_zero_div_err(x):
+        x += 1
+        try:
+            try:
+                x += 2
+                raise ZeroDivisionError("")
+            except ZeroDivisionError:
+                x += 3
+                raise  # RAISE_VARARGS(0)
+        except:
+            x += 4
+        return x + 5
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_1(x):
+        x += 1
+        try:
+            try:
+                x += 2
+            except:
+                x += 3
+            else:
+                x += 4
+                raise NotImplementedError  # RAISE_VARARGS(1)
+                x += 5
+        except:
+            x += 6
+        return x + 7
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_2(x):
+        x -= 10
+        try:
+            try:
+                x -= 300
+            finally:
+                x -= 400
+                raise ValueError from None  # RAISE_VARARGS(2)
+        except ValueError:
+            x -= 500
+
+        return x - 600
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_1_2(x):
+        try:
+            x += 1
+            try:
+                x /= 2
+                raise NameError  # RAISE_VARARGS(1)
+                x *= 3
+            except NameError as e:
+                x -= 4
+                raise TimeoutError("TESTING") from e  # RAISE_VARARGS(2)
+        except:
+            x /= 5
+        return x + 6
+
+    @staticmethod
+    @check_no_breakgraph
+    def argc_equal_to_1_0(x):
+        try:
+            try:
+                x -= 1
+                raise ValueError("TESTING")  # RAISE_VARARGS(1)
+                x += 2
+            except NotImplementedError:
+                x /= 3
+                raise  # RAISE_VARARGS(0)
+        except (KeyError, IndexError):
+            x *= 4
+        except ValueError:
+            x += 5
+        return x
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_RAISE_VARARGS_argc(self):
+        self.assert_results(
+            self.argc_equal_to_0_wo_exception, paddle.to_tensor(0.01)
+        )
+        self.assert_results(
+            self.argc_equal_to_0_zero_div_err, paddle.to_tensor(0.02)
+        )
+        self.assert_results(
+            self.argc_equal_to_0_simulating_zero_div_err, paddle.to_tensor(0.03)
+        )
+        self.assert_results(self.argc_equal_to_1, paddle.to_tensor(0.04))
+        self.assert_results(self.argc_equal_to_2, paddle.to_tensor(0.05))
+        self.assert_results(self.argc_equal_to_1_2, paddle.to_tensor(0.06))
+        self.assert_results(self.argc_equal_to_1_0, paddle.to_tensor(0.07))
+
+
+class TestException(TestCaseBase):
+    @staticmethod
+    def create_builtin_exception(x):
+        def identity(e):
+            return e
+
+        x += 1
+        value_error = ValueError()
+        identity(value_error)
+        x += 2
+        type_error = TypeError("")
+        identity(type_error)
+        x += 3
+        key_error = KeyError("")
+        identity(key_error)
+        x += 4
+        exception = Exception("")
+        identity(exception)
+        x += 5
+        unicode_translate_error = UnicodeTranslateError("", -1, -1, "")
+        identity(unicode_translate_error)
+        x += 6
+        return x
+
+    @staticmethod
+    def create_user_defined_exception(x):
+        # TODO: Need to support user-defined exception
+        return x
+
+    @check_no_breakgraph
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_dispatch(self):
+        self.assert_results(
+            self.create_builtin_exception, paddle.to_tensor(111.0)
+        )
+        self.assert_results(
+            self.create_user_defined_exception, paddle.to_tensor(222.0)
+        )
+
+
+class TestTryExcept(TestCaseBase):
+    # try ... except ...
+    # ---------------- test raising exception directly ----------------
+    @staticmethod
+    def raise_value_error_obj():
+        raise ValueError("Test whether raising `ValueError`")
+
+    @staticmethod
+    def raise_value_error_cls():
+        raise ValueError
+
+    @staticmethod
+    def raise_asserterror(x):
+        assert x, "Test AssertionError"
+
+    # Since the exceptions are not handled, fallback is permitted.
+    @strict_mode_guard(False)
+    def test_exception_raising(self):
+        with self.assertRaisesRegex(
+            ValueError, "Test whether raising `ValueError`"
+        ):
+            symbolic_translate(self.raise_value_error_obj)()
+
+        with self.assertRaisesRegex(ValueError, ""):
+            symbolic_translate(self.raise_value_error_cls)()
+
+        with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
+            symbolic_translate(self.raise_asserterror)(False)
+
+        with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
+            symbolic_translate(self.raise_asserterror)(paddle.to_tensor(0))
+
+    # ---------------- without error ----------------
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_wo_error(x):
+        try:
+            x = x + 1
+        except:
+            x = x * 2
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_wo_error(x):
+        try:
+            x = x + 1
+        except Exception:
+            x = x * 2
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_wo_error(x):
+        try:
+            x = x + 1
+        except Exception as e:
+            x = x * 2
+        return x
+
+    # ---------------- with error ----------------
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_with_error_obj(x):
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError(f"{__class__.__name__}")
+            x = x * 3
+        except:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_with_error_cls(x):
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError
+            x = x * 3
+        except:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_with_error(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        x = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except Exception:
+            x = x * 2
+        return x
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_error(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except ValueError as e:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_error_tuple(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except (ValueError, KeyError, NotImplementedError) as e:
+            y = x * 2
+        return y
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_unmatched_error(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise ValueError("TESTING!")
+            x = x * 3
+        except KeyError as e:
+            y = x * 2
+        return y + 3
+
+    @staticmethod
+    @check_no_breakgraph
+    def try_except_exception_as_e_with_matched_error_reraise(x):
+        # test `JUMP_IF_NOT_EXC_MATCH`
+        y = x + 3
+        try:
+            x = x + 1
+            raise IndexError("TESTING!")
+            x = x * 3
+        except IndexError as e:
+            y = x * 2
+            raise LookupError("TESTING!")
+        return y + 3
+
+    @strict_mode_guard(NOT_ALLOW_FALLBACK)
+    def test_try_except(self):
+        print(f"NOT_ALLOW_FALLBACK: {NOT_ALLOW_FALLBACK}")
path: test/sot/test_24_exceptions.py
user: login: SigureMo
body: 这里是？
created_at: 2025-05-22T13:06:21Z
author_association: MEMBER
diff_hunk: @@ -209,5 +930,19 @@ def try_assert_except(x):
         self.assert_results(try_assert_except, paddle.to_tensor(10))
 
 
+class TestGuard(TestCaseBase):
+    @strict_mode_guard(False)
+    @check_no_breakgraph
+    def test_guard_run(self):
+        def fn():
+            try:
+                paddle.jit.sot.psdb.breakgraph()
+                raise ValueError
+            except ValueError:
+                print("Error caught!")
path: test/sot/test_24_exceptions.py
user: login: SigureMo
body: 这里要不换成 return 吧，非必要还是不要在单测加 `print`
created_at: 2025-05-22T13:08:11Z
author_association: MEMBER

PR comments:
user: login: paddle-bot[bot]
created_at: 2025-05-19T07:39:23Z
body: 你的PR提交成功，感谢你对开源项目的贡献!
请关注后续CI自动化测试结果，详情请参考[Paddle-CI手册](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/dev_guides/git_guides/paddle_ci_manual_cn.html)。
Your PR has been submitted. Thanks for your contribution!
Please wait for the result of CI firstly. See [Paddle CI Manual](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/dev_guides/git_guides/paddle_ci_manual_cn.html) for details.
author_association: NONE
user: login: SigureMo
created_at: 2025-05-19T07:51:44Z
body: 后续异常支持标题统一添加 `[Exception]`，以便区分
author_association: MEMBER
user: login: SigureMo
created_at: 2025-05-21T15:21:57Z
body: > 以下是最小复现代码

```python
def fn():
    try:
        psdb.breakgraph()
        raise ValueError
    except ValueError:
        print("Error catched!")
```

这应该才是最小复现样例（call breakgraph），这个是可以加到单测里的
author_association: MEMBER
user: login: SigureMo
created_at: 2025-05-21T15:44:02Z
body: 另外 #72827 已经退掉 3.8 了，这个 PR 就可以把 `ALREADY_SUPPORTED_EXCEPTION` 里的 `>= 3.8` 删掉了
author_association: MEMBER
user: login: DrRyanHuang
created_at: 2025-05-22T08:22:01Z
body: UPDATE：0604 DONE AT https://github.com/PaddlePaddle/Paddle/pull/73030

---
TODO：这个单测后续添加
```python
class TestBuiltinFunctionRaiseExceptionGuard(TestCaseBase):
    def test_guard_run(self):
        def foo(x):
            1 / x

        self.assert_results(foo, 1)
        self.assert_exceptions(
            ZeroDivisionError,
            "division by zero",
            foo,
            0,
        )
```


author_association: CONTRIBUTOR