keras-team/keras · error · ValueError

For `padding='same'`, `output_size` width

Error message

For `padding='same'`, `output_size` width ({W}) must be in the range ((gW-1)*pW, gW*pW], i.e. ({static_gW * pW - pW}, {static_gW * pW}]. Got: gW={static_gW}, pW={pW}.

What it means

In keras.ops.image reconstruct_patches (2D), padding='same' re-crops a padded reconstruction down to output_size. That crop is only consistent when the requested width W lies in ((gW-1)*pW, gW*pW], where gW is the patch-grid width and pW the patch width. Outside that window no 'same' extraction could have produced this grid for that image size, so the op raises.

Solutions

  1. Pass the exact width of the image that was originally patched (extract_patches input width) — it always satisfies the range
  2. Otherwise pick any W in ((gW-1)*pW, gW*pW], e.g. the full grid width gW*pW
  3. Recompute the grid: for same-padding extraction gW = ceil(W_original / pW); use that to sanity-check
  4. If you need an output not covered by the grid, switch to padding='valid' with exact size*grid

Example fix

# before
reconstruct_patches(patches, size=(8,8), output_size=(20,20), padding='same')
# gW=4, pW=8 -> W must be in (24,32]

# after
reconstruct_patches(patches, size=(8,8), output_size=(20,28), padding='same')
Defensive patterns

Strategy: validation

Validate before calling

gW, pW = int(patches.shape[2]), size[1]
assert (gW-1)*pW < output_size[1] <= gW*pW, 'W out of same-range'  # if gW static

Type guard

def same_w_ok(patches, size, output_size) -> bool:
    gW = patches.shape[2]
    return not isinstance(gW, int) or ((gW-1)*size[1] < output_size[1] <= gW*size[1])

Prevention

When it happens

Trigger: keras.ops.image.reconstruct_patches(patches, size, output_size, padding='same') with output_size width <= (gW-1)*pW or > gW*pW, e.g. gW=4, pW=8 but W=20 (needs 24<W<=32) or W=40.

Common situations: Reconstructing patches extracted with different padding/strides than assumed; passing a resized image size instead of the original extract-time width; swapping height/width in output_size; hardcoding output_size for a variable patch grid.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


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

Appendix: source

Thrown at keras/src/ops/image.py:1295

    x = backend.numpy.transpose(x, axes=(0, 1, 3, 2, 4, 5))
    x = backend.numpy.reshape(x, (B, gH * pH, gW * pW, C))

    if padding == "same":
        static_gH = patches.shape[1]
        static_gW = patches.shape[2]
        if isinstance(static_gH, int) and not (
            static_gH * pH - pH < H <= static_gH * pH
        ):
            raise ValueError(
                f"For `padding='same'`, `output_size` height ({H}) must "
                f"be in the range ((gH-1)*pH, gH*pH], i.e. "
                f"({static_gH * pH - pH}, {static_gH * pH}]. "
                f"Got: gH={static_gH}, pH={pH}."
            )
        if isinstance(static_gW, int) and not (
            static_gW * pW - pW < W <= static_gW * pW
        ):
            raise ValueError(
                f"For `padding='same'`, `output_size` width ({W}) must "
                f"be in the range ((gW-1)*pW, gW*pW], i.e. "
                f"({static_gW * pW - pW}, {static_gW * pW}]. "
                f"Got: gW={static_gW}, pW={pW}."
            )
        pad_total_h = gH * pH - H
        pad_total_w = gW * pW - W
        begin = [0, pad_total_h // 2, pad_total_w // 2, 0]
        out_shape = [B, H, W, C]
        x = ops.slice(x, begin, out_shape)
    else:
        if gH * pH != H or gW * pW != W:
            raise ValueError(
                f"`padding='valid'` requires output_size to equal "
                f"size * grid. Got output_size=({H},{W}), "
                f"grid=({gH},{gW}), size=({pH},{pW})."
            )

View on GitHub (pinned to 7a34a03db6)