TensorFlow
Python
datasets
arrays
error-handling

Converting a list of unequally shaped arrays to Tensorflow 2 Dataset ValueError Can't convert non-rectangular Python sequence to Tensor

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The error ValueError: Can't convert non-rectangular Python sequence to Tensor means TensorFlow tried to build a dense tensor from elements that do not all have the same shape. The fix is not to fight the error message, but to choose the right representation: pad the data, use ragged tensors, or yield samples through a generator with an explicit signature.

Core Sections

Why the error happens

A normal TensorFlow tensor is rectangular. Every row must have the same length, every image in a batch must have the same height and width, and every nested dimension must line up.

This fails:

python
1import tensorflow as tf
2
3samples = [[1, 2, 3], [4, 5], [6]]
4
5dataset = tf.data.Dataset.from_tensor_slices(samples)

TensorFlow cannot turn that list into one dense tensor because the rows do not align.

Solution 1: pad to a common shape

If your model expects dense tensors, padding is often the best fix.

python
1import tensorflow as tf
2
3samples = [[1, 2, 3], [4, 5], [6]]
4
5ragged = tf.ragged.constant(samples)
6padded = ragged.to_tensor(default_value=0)
7
8dataset = tf.data.Dataset.from_tensor_slices(padded)
9
10for row in dataset:
11    print(row.numpy())

Output:

text
[1 2 3]
[4 5 0]
[6 0 0]

Padding works well when the model can ignore the padding value or when you also carry a mask.

Solution 2: use ragged tensors when variable length is real data

If variable length is meaningful and you do not want padding immediately, use a RaggedTensor.

python
1import tensorflow as tf
2
3samples = [[1, 2, 3], [4, 5], [6]]
4ragged = tf.ragged.constant(samples)
5
6print(ragged)

Ragged tensors are useful for text, token sequences, or other naturally variable-length examples. The limitation is that not every TensorFlow operation or model input path handles ragged data equally well, so you still need to check compatibility with the rest of your pipeline.

Solution 3: build the dataset from a generator

If each sample has a different shape and you want to keep them separate until a later batching step, from_generator is often the most flexible approach.

python
1import numpy as np
2import tensorflow as tf
3
4samples = [
5    np.array([1, 2, 3], dtype=np.int32),
6    np.array([4, 5], dtype=np.int32),
7    np.array([6], dtype=np.int32),
8]
9
10def gen():
11    for sample in samples:
12        yield sample
13
14dataset = tf.data.Dataset.from_generator(
15    gen,
16    output_signature=tf.TensorSpec(shape=(None,), dtype=tf.int32),
17)
18
19for row in dataset:
20    print(row.numpy())

This works because the dataset is no longer created by forcing Python to become one rectangular tensor up front.

Batch variable-length elements carefully

Once you have variable-length elements in a dataset, plain .batch() may fail for the same reason as before. Use padded_batch() when you eventually need dense batches.

python
1dataset = dataset.padded_batch(2, padded_shapes=[None], padding_values=0)
2
3for batch in dataset:
4    print(batch.numpy())

That is the standard pattern for sequence data in TensorFlow input pipelines.

Common Pitfalls

  • Using from_tensor_slices on nested Python data that is not actually rectangular.
  • Padding the data without choosing a padding value that the model can safely ignore.
  • Assuming ragged tensors will work automatically with every downstream model or TensorFlow op.
  • Fixing single examples but then calling .batch() later and hitting the same shape problem again.
  • Hiding the real shape issue with object-dtype NumPy arrays instead of choosing an explicit TensorFlow representation.

Summary

  • The error means TensorFlow was asked to build a dense tensor from unequal shapes.
  • Use padding when the model expects dense rectangular input.
  • Use ragged tensors when variable length is a real property of the data.
  • Use from_generator when you need to yield uneven samples without converting them up front.
  • If you batch variable-length items later, prefer padded_batch() instead of ordinary batch().

Course illustration
Course illustration

All Rights Reserved.