keras-team/keras · error · ValueError

Input data in `NumpyArrayIterator` should have rank 4. You p

Error message

Input data in `NumpyArrayIterator` should have rank 4. You passed an array with shape {self.x.shape}

What it means

NumpyArrayIterator requires a rank-4 array (batch, rows, cols, channels) or (batch, channels, rows, cols). Arrays of other ranks are rejected.

Source

Thrown at keras/src/legacy/preprocessing/image.py:616

                    "sorted by the label, you might want "
                    "to shuffle them."
                )

            if subset == "validation":
                x = x[:split_idx]
                x_misc = [np.asarray(xx[:split_idx]) for xx in x_misc]
                if y is not None:
                    y = y[:split_idx]
            else:
                x = x[split_idx:]
                x_misc = [np.asarray(xx[split_idx:]) for xx in x_misc]
                if y is not None:
                    y = y[split_idx:]

        self.x = np.asarray(x, dtype=self.dtype)
        self.x_misc = x_misc
        if self.x.ndim != 4:
            raise ValueError(
                "Input data in `NumpyArrayIterator` "
                "should have rank 4. You passed an array "
                f"with shape {self.x.shape}"
            )
        channels_axis = 3 if data_format == "channels_last" else 1
        if self.x.shape[channels_axis] not in {1, 3, 4}:
            warnings.warn(
                f"NumpyArrayIterator is set to use the data format convention"
                f' "{data_format}" (channels on axis {channels_axis})'
                ", i.e. expected either 1, 3, or 4 channels "
                f"on axis {channels_axis}. "
                f"However, it was passed an array with shape {self.x.shape}"
                f" ({self.x.shape[channels_axis]} channels)."
            )
        if y is not None:
            self.y = np.asarray(y)
        else:
            self.y = None

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Reshape x to (N, H, W, C) e.g. x[..., np.newaxis] for grayscale
  2. For a single image use np.expand_dims(img, axis=0)
  3. Check data_format ('channels_last' default) matches your axis order

Example fix

// before
gen.flow(x_train_flat, y_train)  # (N, 784)
// after
x = x_train_flat.reshape(-1, 28, 28, 1)
gen.flow(x, y_train)
Defensive patterns

Strategy: validation

Validate before calling

x = np.asarray(x)
assert x.ndim == 4, x.shape

Type guard

def is_rank4(a): return np.asarray(a).ndim == 4

Try / catch

try: gen.flow(x, y)
except ValueError as e: if 'rank 4' in str(e): x = x.reshape(x.shape[0], *x.shape[1:]) if x.ndim==3 else ...

Prevention

When it happens

Trigger: Passing a single image (rank 3), a flat vector of pixels (rank 2), or a batch of 5D video frames to gen.flow(x, ...).

Common situations: Forgetting np.expand_dims(x, 0) for a single image; loading raw MNIST flattened to (60000, 784); wrong data_format vs array layout.

Related errors


AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25). Data as JSON: /api/errors/679a82df79e0731e. Report an issue: GitHub.