Fix: InvalidArgumentError — 'dtype' bfloat16 Not in List of Allowed Values
Quick answer
This error means the specific TensorFlow op you called has no bfloat16 kernel — not that bfloat16 is invalid (it is a real dtype). TensorFlow registers kernels per op and per dtype, and many ops only accept uint8/int32/int64/half/float/double. Fix it by casting to a supported dtype for that op: x = tf.cast(x, tf.float32), run the op, then cast back if downstream needs bfloat16. Casting bfloat16→float32 is lossless. Better yet, use tf.keras.mixed_precision.set_global_policy('mixed_bfloat16') so Keras handles dtype placement per layer.
Short answer: This error does not mean bfloat16 is invalid — it's a real dtype. It means the specific op you called has no bfloat16 kernel. Cast to float32 for that op with tf.cast, or use the mixed_bfloat16 policy so Keras places dtypes for you.
InvalidArgumentError: Value for attr 'dtype' of bfloat16 is not in the
list of allowed values: uint8, int32, int64, half, float, double
What's really happening
bfloat16 is a fully supported TensorFlow dtype. But TensorFlow doesn't implement every op for every dtype — kernels are registered per (operation, dtype) pair. When you pass a bfloat16 tensor to an op whose kernel list is uint8, int32, int64, half, float, double, there's simply no bfloat16 implementation to dispatch to, so you get InvalidArgumentError.
The "allowed values" in the message aren't TensorFlow's global dtype list — they're that op's registered kernels.
Fix: cast for the failing op
Cast to float32 before the op, then back afterward only if needed. Because bfloat16 shares float32's 8-bit exponent, widening is lossless:
import tensorflow as tf
x = tf.constant([1.0, 2.0, 3.0], dtype=tf.bfloat16)
# x = some_op(x) # raises InvalidArgumentError
x32 = tf.cast(x, tf.float32)
y = some_op(x32) # runs fine
y = tf.cast(y, tf.bfloat16) # cast back if downstream expects bfloat16Better: let mixed precision place dtypes
If you reached bfloat16 for training speed, don't hand-cast everywhere — use the mixed-precision policy. Keras runs most layers in bfloat16 while keeping numerically sensitive ops (softmax, loss, weight updates) in float32:
tf.keras.mixed_precision.set_global_policy("mixed_bfloat16")
# build/train your model normallyMake the final layer's output float32 explicitly for numerical safety:
outputs = tf.keras.layers.Dense(10)(x)
outputs = tf.keras.layers.Activation("softmax", dtype="float32")(outputs)When bfloat16 is worth it
On TPUs and recent NVIDIA GPUs (Ampere+), bfloat16 roughly halves memory and speeds up training with almost no accuracy loss. On older hardware there's no speed benefit, so it just adds compatibility friction like this error.
Common traps
- Reading the message as "bfloat16 is invalid" — it's op-specific, not global.
- Casting to
float16instead —float16has a smaller exponent thanbfloat16and can overflow; usefloat32. - Manual casts when you meant mixed precision — the policy API is cleaner and safer.
Related guides
Sources
Key takeaways
- •bfloat16 IS a valid TensorFlow dtype — this error is about ONE op lacking a bfloat16 kernel.
- •Kernels are registered per (op, dtype); the allowed list in the message is exactly what that op supports.
- •Fix: tf.cast(x, tf.float32) before the failing op; cast back afterward only if needed.
- •bfloat16→float32 is lossless (same 8-bit exponent, fewer mantissa bits) — casting up never overflows.
- •Prefer mixed_bfloat16 policy over manual casts — Keras keeps sensitive ops (softmax/loss) in float32 for you.
Frequently asked questions
Why is bfloat16 'not in the list of allowed values' if TensorFlow supports it?
Because TensorFlow registers kernels per operation and per dtype. An op only accepts a dtype if a kernel was implemented and registered for that pair. Many ops — often older or less common ones — have no bfloat16 kernel, so passing one raises InvalidArgumentError even though the dtype itself is perfectly valid.
How do I fix the error?
Cast to a supported dtype before the failing op, usually float32: x = tf.cast(x, tf.float32). Run the op, then cast the result back to bfloat16 only if the rest of your pipeline needs it. bfloat16→float32 is lossless.
Will casting to float32 hurt accuracy?
No. bfloat16 has the same 8-bit exponent as float32 but only 7 mantissa bits, so widening to float32 loses nothing — it only adds precision. The cost is more memory and possibly slower execution for that one op.
Is there a cleaner fix than casting everywhere?
Yes — Keras mixed precision: tf.keras.mixed_precision.set_global_policy('mixed_bfloat16'). Keras then chooses dtypes per layer and keeps numerically sensitive operations like softmax and loss in float32 automatically, so you don't hand-place casts.
Software Engineering Leader & Technical Author · Updated August 26, 2026