TensorFlow
dynamic_rnn
rank error
neural networks
machine learning

Rank error in tf.nn.dynamic_rnn

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

A rank error in tf.nn.dynamic_rnn almost always means one of the tensors has the wrong number of dimensions. The most common problem is the input tensor: dynamic_rnn expects a 3-D input shaped like batch, time, and features, but many bugs feed it a 2-D matrix or a tensor with the axes in the wrong order.

What dynamic_rnn Expects

tf.nn.dynamic_rnn is a TensorFlow 1.x style API for recurrent models. Its core input is usually shaped as:

  • '[batch_size, max_time, feature_dim] when time_major=False'
  • '[max_time, batch_size, feature_dim] when time_major=True'

That means rank 3, not rank 2.

A minimal working example using the compatibility API looks like this:

python
1import tensorflow as tf
2
3tf.compat.v1.disable_eager_execution()
4
5batch_size = 4
6max_time = 10
7feature_dim = 8
8hidden_size = 16
9
10inputs = tf.compat.v1.placeholder(tf.float32, [None, None, feature_dim])
11cell = tf.compat.v1.nn.rnn_cell.LSTMCell(hidden_size)
12outputs, state = tf.compat.v1.nn.dynamic_rnn(cell, inputs, dtype=tf.float32)
13
14with tf.compat.v1.Session() as sess:
15    sess.run(tf.compat.v1.global_variables_initializer())
16    x = tf.random.normal((batch_size, max_time, feature_dim)).eval()
17    y = sess.run(outputs, feed_dict={inputs: x})
18    print(y.shape)

If inputs were shaped [None, feature_dim], TensorFlow would complain because the time dimension is missing.

The Most Common Rank Mistake

A lot of code starts from tabular data shaped like [batch_size, feature_dim] and tries to feed it directly into an RNN. That is not enough information for a sequence model, because there is no explicit time axis.

Wrong idea:

python
inputs = tf.compat.v1.placeholder(tf.float32, [None, 8])

Corrected idea for sequences of length 1:

python
inputs = tf.compat.v1.placeholder(tf.float32, [None, 1, 8])

Or, if you already have a 2-D tensor and want to add a time dimension deliberately:

python
1import tensorflow as tf
2
3x = tf.compat.v1.placeholder(tf.float32, [None, 8])
4x_3d = tf.expand_dims(x, axis=1)

Now x_3d has shape [batch_size, 1, feature_dim], which satisfies the rank requirement.

time_major=True Changes Axis Order

Another source of rank or shape confusion is time_major=True. The input is still rank 3, but the first two axes swap roles.

python
1outputs, state = tf.compat.v1.nn.dynamic_rnn(
2    cell,
3    inputs,
4    time_major=True,
5    dtype=tf.float32,
6)

If you enable time_major=True, your input should look like [time, batch, features]. Many bugs happen when developers set time_major=True for performance reasons but keep feeding [batch, time, features] tensors.

sequence_length Has Its Own Shape Rule

The sequence_length argument must be a rank-1 vector with one length per batch element.

python
sequence_length = tf.compat.v1.placeholder(tf.int32, [None])

If you accidentally pass a scalar, matrix, or incorrectly broadcasted tensor, dynamic_rnn can fail with a rank or shape error that looks unrelated at first glance.

A full example:

python
1sequence_length = tf.compat.v1.placeholder(tf.int32, [None])
2outputs, state = tf.compat.v1.nn.dynamic_rnn(
3    cell,
4    inputs,
5    sequence_length=sequence_length,
6    dtype=tf.float32,
7)

The batch size of sequence_length must match the batch size of inputs.

Debug Shapes Before Running the Session

When working with TensorFlow 1.x style graphs, it helps to inspect static shapes early.

python
print(inputs.shape)
print(sequence_length.shape)

If the shape is partially dynamic, inspect runtime shapes too:

python
runtime_shape = tf.shape(inputs)

When a rank error appears, the fastest path is usually to verify:

  • input rank is 3
  • feature dimension matches what the cell expects
  • 'sequence_length rank is 1'
  • 'time_major matches the actual tensor layout'

If You Are Using Modern TensorFlow

If you are writing new code, prefer tf.keras.layers.LSTM, GRU, or SimpleRNN. They hide much of the low-level shape handling that made dynamic_rnn error-prone.

python
1import tensorflow as tf
2
3model = tf.keras.Sequential([
4    tf.keras.layers.Input(shape=(10, 8)),
5    tf.keras.layers.LSTM(16),
6])
7
8x = tf.random.normal((4, 10, 8))
9print(model(x).shape)

The same rank principle still applies, but the API surface is easier to reason about.

Common Pitfalls

The biggest pitfall is feeding a 2-D tensor into an API that expects a 3-D sequence tensor.

Another common issue is mixing up batch-major and time-major layouts after enabling time_major=True.

Developers also often forget that sequence_length is a rank-1 vector, not a scalar or matrix.

Finally, dynamic_rnn is a legacy API. If you are starting new work, use Keras recurrent layers unless you have a specific reason to stay with TensorFlow 1.x graph code.

Summary

  • 'tf.nn.dynamic_rnn expects a rank-3 input tensor.'
  • The usual shape is [batch, time, features] unless time_major=True is enabled.
  • 'sequence_length must be a rank-1 vector with one value per batch item.'
  • Add a time axis explicitly if your data starts as rank 2.
  • For new TensorFlow code, prefer Keras RNN layers over legacy dynamic_rnn.

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.