TensorFlow
AttributeError
Tensor
Python
Machine Learning

TensorFlow AttributeError 'Tensor' object has no attribute 'shape'

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

In modern TensorFlow, a real tf.Tensor normally does have a .shape attribute. So if you see AttributeError: 'Tensor' object has no attribute 'shape', the usual cause is not that TensorFlow forgot the attribute. The usual cause is that the object is not the kind of tensor you think it is, or that your code really needs runtime shape logic rather than static shape metadata.

Static Shape Versus Runtime Shape

TensorFlow exposes shape in two different ways:

  • 'tensor.shape for static metadata known to Python'
  • 'tf.shape(tensor) for runtime shape computed inside TensorFlow'

Example:

python
1import tensorflow as tf
2
3x = tf.constant([[1, 2, 3], [4, 5, 6]])
4
5print(x.shape)            # static shape
6print(tf.shape(x))        # runtime tensor
7print(tf.shape(x).numpy())

If your code is building layers or validating dimensions in Python, .shape is usually appropriate. If your code runs inside a traced graph or depends on dynamic batch sizes, tf.shape(...) is often the right tool instead.

Verify the Object Type First

A large share of these errors comes from one simple bug: the value is not actually a native TensorFlow tensor.

Start with:

python
print(type(x))

If the object came from:

  • a wrapper library
  • an older compatibility layer
  • a custom pipeline object
  • a symbolic placeholder in unexpected form

then .shape may not behave the way you expect.

A quick diagnostic helper:

python
1import tensorflow as tf
2
3def inspect_value(value):
4    print("type:", type(value))
5    print("has .shape:", hasattr(value, "shape"))
6
7    if hasattr(value, "shape"):
8        print("static shape:", value.shape)
9
10    try:
11        print("runtime shape:", tf.shape(value))
12    except Exception as exc:
13        print("tf.shape failed:", exc)

This separates "not a TensorFlow tensor" from "dynamic shape confusion" very quickly.

TensorFlow 1.x Compatibility Code

In older graph-mode code, get_shape() is common and still valid in compatibility paths.

python
1import tensorflow as tf
2
3tf.compat.v1.disable_eager_execution()
4
5x = tf.compat.v1.placeholder(tf.float32, shape=[None, 4])
6
7print(x.get_shape())
8print(tf.shape(x))

If you are maintaining TensorFlow 1 style code, do not assume every modern eager-mode pattern applies directly. Graph-mode code often needs a different mental model.

Keras Symbolic Tensors

Inside Keras model-building code, tensors can be symbolic. They may expose a shape, but not every dimension is a concrete Python integer.

python
1import tensorflow as tf
2
3inputs = tf.keras.Input(shape=(32,))
4hidden = tf.keras.layers.Dense(16)(inputs)
5
6print(hidden.shape)

This works, but the batch dimension may remain symbolic. If your code tries to use shape information for dynamic control flow, switch to TensorFlow ops rather than plain Python branching.

Use tf.shape in Graph-Style Logic

When the code depends on actual runtime sizes, prefer tf.shape.

python
1import tensorflow as tf
2
3@tf.function
4def first_dim(x):
5    return tf.shape(x)[0]
6
7value = tf.constant([[1.0, 2.0], [3.0, 4.0]])
8print(first_dim(value).numpy())

This is especially important in:

  • '@tf.function'
  • custom layers
  • dynamic batching
  • dataset pipelines

Static .shape metadata is often not enough in those contexts.

Common Migration Mistake

A frequent migration bug is code that assumes .shape is always a plain tuple-like value that can drive ordinary Python logic. In eager mode that often works. In traced or symbolic code, it may not.

If your logic depends on TensorFlow execution, keep shape handling inside TensorFlow operations. If your logic is just debugging or validation at Python level, .shape is fine.

The key is to decide which of those two worlds your code is actually in.

Common Pitfalls

  • Assuming every object named tensor is a native tf.Tensor.
  • Using .shape when the real requirement is runtime shape from tf.shape(...).
  • Mixing TensorFlow 1 graph-mode assumptions with TensorFlow 2 eager-style code.
  • Treating symbolic Keras dimensions as concrete integers too early.
  • Debugging shape issues without printing the actual object type first.

Summary

  • A real modern TensorFlow tensor normally supports .shape.
  • Use .shape for static metadata and tf.shape(...) for runtime dimensions.
  • If .shape fails, verify that the object is actually the tensor type you think it is.
  • TensorFlow 1 compatibility code and symbolic Keras code need slightly different shape reasoning.
  • Most fixes come from clarifying object type and whether the code needs static or dynamic shape information.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.