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
- Print
.shapeof every operand on the failing line. - Line the shapes up from the right; each pair must be equal or contain a 1.
- Reshape with
[:, None],keepdims=True,.reshape(-1, 1)or.T. - If two 1-D arrays differ in length, find where one was filtered.
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.