jax-ml/jax · error · nb::value_error
Cannot enter TracebackScope recursively.
Error message
Cannot enter TracebackScope recursively.
What it means
TracebackScope.__enter__ (used to trim JAX internal frames from tracebacks) refuses to nest: entering a scope while another is already active on this thread throws a value error, because it tracks a single saved stop frame.
Source
Thrown at jaxlib/traceback.cc:218
// truncating any tracebacks captured within its scope to the call site.
class TracebackScope {
public:
TracebackScope() = default;
TracebackScope(const TracebackScope& other) = delete;
TracebackScope(TracebackScope&& other) noexcept = default;
TracebackScope& operator=(const TracebackScope&) = delete;
TracebackScope& operator=(TracebackScope&&) noexcept = default;
~TracebackScope() {
if (old_stop_frame_) {
CHECK(PyGILState_Check());
old_stop_frame_ = {};
}
}
// Captures the current stop frame and sets a new one at the caller's caller.
TracebackScope& Enter() {
if (old_stop_frame_) {
throw nb::value_error("Cannot enter TracebackScope recursively.");
}
old_stop_frame_ = nb::borrow<nb::object>(
reinterpret_cast<PyObject*>(Traceback::GetStopFrame()));
PyThreadState* thread_state = PyThreadState_GET();
if (thread_state) {
// We get the frame of the caller of the __enter__ method.
nb::object frame = nb::steal<nb::object>(
reinterpret_cast<PyObject*>(PyThreadState_GetFrame(thread_state)));
if (frame) {
Traceback::SetStopFrame(reinterpret_cast<PyFrameObject*>(frame.ptr()));
}
}
return *this;
}
// Restores the previous stop frame.
void Exit(nb::args args) {
Traceback::SetStopFrame(View on GitHub (pinned to 1e1c6a8fc0)
Solutions
- Don't nest TracebackScope context managers; use one at the outermost level
- Let JAX manage TracebackScope internally and remove manual usage
- Refactor so inner code doesn't open its own scope
Example fix
# before
with TracebackScope():
with TracebackScope(): # recursive enter
jax.numpy.sin(1.0)
# after
with TracebackScope():
jax.numpy.sin(1.0) Defensive patterns
Strategy: validation
Validate before calling
if not applicable
Try / catch
try:
with TracebackScope():
run()
except ValueError as e:
if 'recursively' in str(e):
run() # scope already active; just run
else:
raise Prevention
- Never nest TracebackScope; enter it once at the outermost layer
- Let JAX manage its own traceback trimming
When it happens
Trigger: Using jaxlib.traceback.TracebackScope as a context manager and entering it again inside the with-block on the same thread, e.g. wrapping code that itself opens a TracebackScope.
Common situations: Library code that composes JAX calls where both caller and callee apply traceback trimming; user code manually using TracebackScope around jax functions that already use it internally.
Related errors
- The traceback property was called on {self._error_repr()}.{s
- Cannot update the mesh of the current resource environment.
- Mesh context manager is disabled.
- code argument must be a code object
- numpy masked arrays are not supported as direct inputs to JA
AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27).
Data as JSON: /api/errors/d424ca7148c3fbbb.
Report an issue: GitHub.