Skip to content
Happy Programming Guide
Start learning
Python

ValueError: Could Not Determine the Shape of Object

NumPy raises this when the data you passed is ragged or contains mixed types. Here is how to find the offending row and the four ways to fix it.

Keys of a mechanical keyboard seen up close

ValueError: could not determine the shape of object type and its cousin setting an array element with a sequence both mean the same thing: NumPy tried to build a rectangular array from data that is not rectangular. Usually one row has a different length from the others, or the data contains a mix of types NumPy cannot reconcile.

Reproducing it#

Python
import numpy as np

rows = [[1, 2, 3], [4, 5], [6, 7, 8]]
np.array(rows)
Output
ValueError: setting an array element with a sequence. The requested array has an
inhomogeneous shape after 1 dimensions.

A NumPy array is a single block of memory with a fixed shape, which is exactly what makes it fast. Rows of different lengths cannot be laid out that way, so NumPy refuses rather than guessing.

Older NumPy versions created an object array with a warning instead. Version 1.24 made it an error, which is why code that worked last year may not now.

Step 1: find the offending row#

Python
from collections import Counter

lengths = [len(row) for row in rows]
print(Counter(lengths))

expected = Counter(lengths).most_common(1)[0][0]

for i, row in enumerate(rows):
    if len(row) != expected:
        print(f"row {i} has {len(row)} items: {row}")

On real data this usually finds one or two rows out of thousands — a truncated record, a header that slipped through, or a line with a missing field.

Check the types too, since a mix can cause the same error:

Python
types = {type(x) for row in rows for x in row}
print(types)

Fix 1: pad to a common length#

Python
import numpy as np


def pad_rows(rows, fill=np.nan):
    width = max(len(row) for row in rows)
    return np.array([list(row) + [fill] * (width - len(row)) for row in rows],
                    dtype=float)


arr = pad_rows([[1, 2, 3], [4, 5], [6, 7, 8]])
print(arr)
Output
[[ 1.  2.  3.]
 [ 4.  5. nan]
 [ 6.  7.  8.]]

Padding with np.nan requires a float array, which is usually fine. NumPy’s nan-aware functions then skip the padding automatically:

Python
print(np.nanmean(arr, axis=1))
print(np.nansum(arr))

Fix 2: truncate to the shortest#

Python
width = min(len(row) for row in rows)
arr = np.array([row[:width] for row in rows])

Right when the extra elements are genuinely surplus — time series of different lengths where you only want the overlapping period, for instance. Wrong when you would be silently discarding data, so check how much you are dropping.

Fix 3: keep them separate#

Python
arrays = [np.array(row) for row in rows]

means = [a.mean() for a in arrays]
total = sum(a.sum() for a in arrays)

If the rows are genuinely independent measurements of different lengths, forcing them into one rectangle is the wrong model. A list of arrays keeps each one fast and loses nothing.

Fix 4: dtype=object#

Python
arr = np.empty(len(rows), dtype=object)
arr[:] = rows

print(arr.shape)     # (3,)
print(arr[1])        # [4, 5]

This works, and it is worth being clear about what you lose. An object array stores Python object pointers, not numbers, so vectorised arithmetic falls back to a Python loop. You get NumPy’s syntax with a list’s performance.

The mixed-types version#

Python
np.array([1, 2, "three"])
# array(['1', '2', 'three'], dtype='<U21')  - everything became a string

This one does not raise. NumPy finds a type everything fits into, and strings win, so your numbers silently become text. Then arithmetic fails somewhere else entirely:

Output
numpy.core._exceptions.UFuncTypeError: ufunc 'add' did not contain a loop with
signature matching types

Be explicit about the type you expect, so a bad value fails immediately:

Python
arr = np.array(values, dtype=float)     # raises on "three"

Or convert leniently and count the failures:

Python
import pandas as pd

numbers = pd.to_numeric(pd.Series(values), errors="coerce")
print(numbers.isna().sum(), "values could not be converted")
arr = numbers.to_numpy(dtype=float)

The pandas version#

Python
import pandas as pd

pd.DataFrame({"a": [1, 2, 3], "b": [4, 5]})
Output
ValueError: All arrays must be of the same length

Same cause, clearer message. Build from a list of dictionaries instead, and pandas fills the gaps:

Python
df = pd.DataFrame([
    {"a": 1, "b": 4},
    {"a": 2, "b": 5},
    {"a": 3},
])
print(df)      # b is NaN in the third row

The machine learning version#

Python
import torch

torch.tensor([[1, 2, 3], [4, 5]])
# ValueError: expected sequence of length 3 at dim 1

Tensors have the same rectangular requirement. Sequences of different lengths — sentences, time series — are the usual cause, and padding is the standard answer:

Python
from torch.nn.utils.rnn import pad_sequence

sequences = [torch.tensor(row) for row in rows]
padded = pad_sequence(sequences, batch_first=True, padding_value=0)

lengths = torch.tensor([len(r) for r in rows])

Keep the lengths alongside the padded tensor. Without them the model cannot tell padding from real zeros, and it will learn from the padding.

Preventing it#

Python
def to_array(rows, expected_width=None, dtype=float):
    """Build a NumPy array, failing with a useful message."""
    lengths = {len(row) for row in rows}

    if len(lengths) > 1:
        counts = Counter(len(row) for row in rows)
        raise ValueError(f"Rows have different lengths: {dict(counts)}")

    width = lengths.pop()
    if expected_width is not None and width != expected_width:
        raise ValueError(f"Expected width {expected_width}, got {width}")

    return np.array(rows, dtype=dtype)

Validating at the point where the data is built gives you a message naming the problem, rather than a NumPy error several functions later.

Questions people ask#

Why did this work in an older NumPy?

Before version 1.24, ragged input produced an object array with a deprecation warning. It is now an error, so the code that “worked” was already doing something you probably did not intend.

Is an object array ever the right answer?

Occasionally — when you want NumPy indexing over genuinely heterogeneous data. Be aware that you lose vectorisation entirely, so a list is often just as good and clearer.

How do I check the shape before converting?

Counter(len(row) for row in rows). One entry means it is rectangular; more than one names the problem immediately.

What is the difference between this and “setting an array element with a sequence”?

Two messages for the same underlying cause, from different code paths inside NumPy. Both mean the input is not rectangular.

Where to go next#

Cleaning data properly before it becomes an arrayRead next

Keep reading

Python

Data Visualization in Python

Choosing the right chart, then building it with matplotlib, pandas or seaborn — plus the design changes that make a chart readable.

5 min read

Python

Python Security

The security work that matters in Python: SQL injection, pickle, subprocess, secrets, dependency scanning and the randomness mistake.

5 min read

Python

Python and Data Science

The four libraries that matter — NumPy, pandas, matplotlib and scikit-learn — and a complete first analysis from loading a CSV to…

5 min read

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *