TensorFlow "triggered tf.function retracing" warning (tested)

WARNING:tensorflow:5 out of the last 5 calls to <function> triggered tf.function retracing means each call built a new graph, usually because you pass Python numbers instead of tensors or a new shape each time. Measured below: 6 traces for 6 calls, down to 1 with tf.constant and 2 with reduce_retracing=True.

1. Reproduce

b1.py calls a @tf.function six times, passing a different Python int each time:

import os; os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
import tensorflow as tf

@tf.function
def scale(x, factor):
    return x * factor

for i in range(6):
    scale(tf.constant([1.0, 2.0]), i)          # Python int: a new graph per value
print("traces:", scale.experimental_get_tracing_count())
WARNING:tensorflow:5 out of the last 5 calls to <function scale at 0x7f1b27e471a0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
WARNING:tensorflow:6 out of the last 6 calls to <function scale at 0x7f1b27e471a0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
traces: 6

It is a warning, not an exception: the results are correct, but every call built a new graph (6 traces for 6 calls), which is slower than plain eager code. Python values (ints, floats, strings, lists) are part of the trace signature, so each new value means a new trace.

2. Fix: pass tensors, and relax shapes

import os; os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
import tensorflow as tf

@tf.function
def scale(x, factor):
    return x * factor

for i in range(6):
    scale(tf.constant([1.0, 2.0]), tf.constant(float(i)))   # tensor arg: one graph
print("traces:", scale.experimental_get_tracing_count())

@tf.function(reduce_retracing=True)
def total(x):
    return tf.reduce_sum(x)

for n in range(1, 7):
    total(tf.ones([n]))                        # new shape every call
print("reduce_retracing traces:", total.experimental_get_tracing_count())
traces: 1
reduce_retracing traces: 2

Count traces yourself with fn.experimental_get_tracing_count(), as above.

Related: TensorFlow Keras errors after Keras 3, pip install tensorflow: no matching distribution found.

Frequently asked questions

What does triggered tf.function retracing mean?

The tf.function built a new graph on (almost) every call. It is a performance warning; results are still correct.

How do I stop tf.function retracing?

Pass tensors instead of Python scalars, define the function once outside loops, and use reduce_retracing=True or an input_signature when shapes change.

How can I count how often a tf.function traced?

Call fn.experimental_get_tracing_count() on the decorated function.

Written with AI assistance. Measured on 2026-10-24 with tensorflow-cpu 2.21.0 and Python 3.13.5 on Linux. The scripts ran verbatim and the output was pasted unedited (TensorFlow startup log lines filtered). PlainTables is our extension; TensorFlow is free.