keras-team/keras · error · ValueError

Cannot do batch_dot on inputs with different batch sizes. Re

Error message

Cannot do batch_dot on inputs with different batch sizes. Received inputs with tf.shapes {x_shape} and {y_shape}.

What it means

batch_dot pairs each sample i of x with sample i of y, so the leading (batch) dimensions of both operands must match when both are known. The function compares x.shape[0] and y.shape[0] and raises when they differ, preventing silent misalignment or accidental broadcasting.

Source

Thrown at keras/src/legacy/backend.py:80

    x_shape = x.shape
    y_shape = y.shape

    x_ndim = len(x_shape)
    y_ndim = len(y_shape)

    if x_ndim < 2 or y_ndim < 2:
        raise ValueError(
            "Cannot do batch_dot on inputs "
            "with rank < 2. "
            f"Received inputs with tf.shapes {x_shape} and {y_shape}."
        )

    x_batch_size = x_shape[0]
    y_batch_size = y_shape[0]

    if x_batch_size is not None and y_batch_size is not None:
        if x_batch_size != y_batch_size:
            raise ValueError(
                "Cannot do batch_dot on inputs "
                "with different batch sizes. "
                "Received inputs with tf.shapes "
                f"{x_shape} and {y_shape}."
            )
    if isinstance(axes, int):
        axes = [axes, axes]

    if axes is None:
        if y_ndim == 2:
            axes = [x_ndim - 1, y_ndim - 1]
        else:
            axes = [x_ndim - 1, y_ndim - 2]

    if py_any(isinstance(a, (list, tuple)) for a in axes):
        raise ValueError(
            "Multiple target dimensions are not supported. "
            "Expected: None, int, (int, int), "

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Align batch sizes: slice or pad the larger tensor so shape[0] matches (e.g. y = y[: x.shape[0]])
  2. Recompute both operands from the same batch instead of caching one
  3. Use drop_remainder=True in your data pipeline so all batches have equal size

Example fix

# before
loss = keras.ops.batch_dot(embeddings, targets)  # (32, d) vs (64, d)

# after
targets = targets[: embeddings.shape[0]]
loss = keras.ops.batch_dot(embeddings, targets)
Defensive patterns

Strategy: validation

Validate before calling

bx, by = x.shape[0], y.shape[0]
if bx is not None and by is not None and bx != by:
    n = min(bx, by)
    x, y = x[:n], y[:n]
out = keras.ops.batch_dot(x, y)

Type guard

def same_batch_size(x, y) -> bool:
    return x.shape[0] is None or y.shape[0] is None or x.shape[0] == y.shape[0]

Prevention

When it happens

Trigger: Calling batch_dot(x, y) where x has shape (32, d) and y has shape (64, d); mixing tensors from different batches or from a split/reshuffle; broadcasting one operand across the batch unintentionally.

Common situations: Contrastive/triplet loss code where positives were sampled with a different batch size; last partial batch in a generator vs a fixed-size target tensor; splitting tensors and losing track of batch size; reusing a cached tensor from another batch.

Related errors


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