NumPy broadcasting error: operands could not be broadcast together with shapes (tested)

ValueError: operands could not be broadcast together with shapes (3,4) (3,) means NumPy could not line the two shapes up: compared from the right, each pair of dimensions must be equal or 1. The usual fix is keepdims=True or [:, None]. Every block below was run on NumPy 2.5.4.

1. The rule, tested

import numpy as np

a = np.ones((3, 4))
for other in (np.ones(4), np.ones((3, 1)), np.ones(3), np.ones((4, 3))):
    try:
        print(other.shape, "->", (a + other).shape)
    except ValueError as e:
        print(other.shape, "-> ValueError:", e)

Output:

(4,) -> (3, 4)
(3, 1) -> (3, 4)
(3,) -> ValueError: operands could not be broadcast together with shapes (3,4) (3,) 
(4, 3) -> ValueError: operands could not be broadcast together with shapes (3,4) (4,3)

NumPy compares shapes from the right. Two dimensions are compatible when they are equal or one of them is 1; a missing dimension counts as 1. So (3,4) with (4,) works (the row is repeated down), and (3,1) works (the column is repeated across). (3,) fails because its 3 is lined up against the 4, not the 3. (4,3) fails because neither pair matches.

2. The classic: subtracting row means

import numpy as np

a = np.ones((3, 4))
row_means = a.mean(axis=1)                 # shape (3,)
try:
    a - row_means
except ValueError as e:
    print("ValueError:", e)
print((a - row_means[:, None]).shape)                 # add an axis
print((a - a.mean(axis=1, keepdims=True)).shape)      # or keepdims

Output:

ValueError: operands could not be broadcast together with shapes (3,4) (3,) 
(3, 4)
(3, 4)

mean(axis=1) drops the axis, leaving shape (3,), which lines up with the columns. Add the axis back with [:, None] (same as np.newaxis) or use keepdims=True, which gives (3,1) and broadcasts across each row.

3. Other forms of the same error

import numpy as np

x = np.arange(5)
y = np.arange(4)
try:
    x * y
except ValueError as e:
    print("ValueError:", e)
try:
    np.where(x > 2, x, y)
except ValueError as e:
    print("ValueError:", e)
try:
    x[np.array([True, False])] = 0
except IndexError as e:
    print("IndexError:", e)
a = np.zeros((2, 3))
try:
    a[:, 0] = [1, 2, 3]
except ValueError as e:
    print("ValueError:", e)

Output:

ValueError: operands could not be broadcast together with shapes (5,) (4,) 
ValueError: operands could not be broadcast together with shapes (5,) (5,) (4,) 
IndexError: boolean index did not match indexed array along axis 0; size of axis is 5 but size of corresponding boolean axis is 2
ValueError: could not broadcast input array from shape (3,) into shape (2,)

Two 1-D arrays of different length never broadcast; usually one was filtered or sliced and the other was not. np.where lists all three shapes. A boolean mask of the wrong length gives an IndexError instead. Assigning into a slice gives "could not broadcast input array from shape (3,) into shape (2,)": a[:, 0] is a column of 2 values, so the right side must have 2 values (or 1).

4. Matrix multiply vs element-wise, and checking shapes up front

import numpy as np

A = np.ones((2, 3))
B = np.ones((2, 3))
try:
    A @ B
except ValueError as e:
    print("ValueError:", e)
print((A @ B.T).shape, (A * B).shape)
print(np.broadcast_shapes((3, 1), (1, 4)))
try:
    np.broadcast_shapes((3, 4), (3,))
except ValueError as e:
    print("ValueError:", e)

Output:

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3)
(2, 2) (2, 3)
(3, 4)
ValueError: shape mismatch: objects cannot be broadcast to a single shape.  Mismatch is between arg 0 with shape (3, 4) and arg 1 with shape (3,).

@ (and np.dot) follows matrix rules, not broadcasting: the inner dimensions must match, so (2,3) @ (2,3) fails and (2,3) @ (3,2) works. If you meant element-wise, use *. np.broadcast_shapes tells you the result shape, or which argument is incompatible, without allocating arrays.

5. Checklist

Related: NumPy RuntimeWarning · LinAlgError: Singular matrix · assignment destination is read-only.

Frequently asked questions

What does 'operands could not be broadcast together' mean?

The array shapes are incompatible: compared from the last dimension backwards, each pair must be equal or one of them must be 1.

How do I subtract the row mean from a 2-D array?

a - a.mean(axis=1, keepdims=True), or a - a.mean(axis=1)[:, None]. Without keepdims the (3,) result lines up with the columns and fails.

Why does A @ B fail when A * B works?

@ is matrix multiplication: the inner dimensions must match ((n,k) @ (k,m)). * is element-wise and uses broadcasting.

Written with AI assistance. Measured on 2026-10-23 in Docker: python:3-alpine (Python 3.14.7) with numpy 2.5.4. Each block was run verbatim and the output pasted unedited. PlainTables is our extension; Python and NumPy are free.