Disabling tf.function decorators for debugging?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
@tf.function can make TensorFlow code much faster by tracing Python into a graph, but graph execution is harder to debug than eager execution. When you are chasing shape errors, Python-side control flow bugs, or confusing stack traces, temporarily disabling graph tracing is often the fastest way to see what the code is actually doing.
The simplest global switch
The most direct debugging tool is tf.config.run_functions_eagerly(True). It tells TensorFlow to execute tf.function bodies eagerly instead of tracing them into graphs.
With eager execution enabled this way, normal Python debugging behavior becomes much easier to reason about. You can inspect values, use breakpoints more naturally, and get clearer tracebacks.
When you are done debugging, switch it back off:
Temporarily remove the decorator
If you only want to debug one function, the simplest option is often to remove @tf.function from that function temporarily.
This is crude, but it is very effective when you need to inspect a specific function without changing global TensorFlow behavior.
Keras-specific debugging
If the problem happens inside a compiled Keras model, run_eagerly=True is often the right knob.
That keeps the training loop in eager mode, which is much easier to debug than a traced training step.
What changes when eager execution is forced
When tf.function runs eagerly, regular Python print, debuggers, and exceptions behave more like normal Python programs. That is the main advantage.
The tradeoff is performance. Graph optimizations, tracing, and some static checks are no longer active in the same way. Debug mode should therefore be temporary.
It is also important to remember that eager execution can hide graph-only behavior differences. A function that works in eager mode may still fail when tracing is turned back on because of Python-side side effects, variable creation rules, or autograph conversion details.
Useful debugging patterns
Even without fully disabling tf.function, a few techniques help.
tf.print and tf.debugging assertions work inside traced functions and are often enough when you do not want to disable graph execution entirely.
One subtle limitation
tf.config.run_functions_eagerly(True) affects tf.function, but it does not turn every TensorFlow subsystem into pure eager Python. Input pipelines, especially those built with tf.data, still have their own execution model. So if the bug lives in a dataset transformation, this flag may not expose it the way you expect.
Common Pitfalls
A common mistake is leaving eager-debug settings enabled in production training code. That can slow training dramatically.
Another issue is assuming that a function proven in eager mode is automatically safe in graph mode. Trace-time restrictions still matter once you re-enable @tf.function.
It is also easy to overuse global eager mode when the real problem is limited to one function. In that case, removing the decorator locally or using run_eagerly=True in Keras is usually more targeted.
Summary
- Use
tf.config.run_functions_eagerly(True)to maketf.functionbodies execute eagerly during debugging. - Remove
@tf.functiontemporarily when you only need to inspect one function. - In Keras,
model.compile(..., run_eagerly=True)is often the most practical debugging switch. - '
tf.printandtf.debuggingutilities are still useful inside traced functions.' - Turn eager debugging back off after the issue is understood so performance returns to normal.

