{"record":{"id":"31e2c73866bdff32","repo":"keras-team/keras","slug":"patches-has-unexpected-rank-for-3d-reconstructio","errorCode":null,"errorMessage":"`patches` has unexpected rank for 3D reconstruction. Expected 4 (unbatched) or 5 (batched). Received shape: {patches.shape}","messagePattern":"`patches` has unexpected rank for 3D reconstruction\\. Expected 4 \\(unbatched\\) or 5 \\(batched\\)\\. Received shape: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/ops/image.py","lineNumber":1362,"sourceCode":"            patches = backend.numpy.transpose(patches, axes=(0, 2, 3, 4, 1))\n        else:\n            raise ValueError(\n                \"`patches` has unexpected rank for 3D channels_first \"\n                \"reconstruction. Expected 4 (unbatched) or 5 (batched). \"\n                f\"Received shape: {patches.shape}\"\n            )\n        result = _reconstruct_patches_3d(\n            patches, size, output_size, strides, padding, \"channels_last\"\n        )\n        if len(result.shape) == 4:\n            return backend.numpy.transpose(result, axes=(3, 0, 1, 2))\n        return backend.numpy.transpose(result, axes=(0, 4, 1, 2, 3))\n\n    pD, pH, pW = size\n    D, H, W = output_size\n\n    if len(patches.shape) not in (4, 5):\n        raise ValueError(\n            \"`patches` has unexpected rank for 3D reconstruction. \"\n            \"Expected 4 (unbatched) or 5 (batched). \"\n            f\"Received shape: {patches.shape}\"\n        )\n\n    _unbatched = False\n    if len(patches.shape) == 4:\n        _unbatched = True\n        patches = backend.numpy.expand_dims(patches, axis=0)\n\n    shp = ops.shape(patches)\n    B, gD, gH, gW = shp[0], shp[1], shp[2], shp[3]\n    static_flat = patches.shape[-1]\n    if static_flat is None:\n        C = shp[4] // (pD * pH * pW)\n    else:\n        if static_flat % (pD * pH * pW) != 0:\n            raise ValueError(","sourceCodeStart":1344,"sourceCodeEnd":1380,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/ops/image.py#L1344-L1380","documentation":"The 3D reconstruction path requires patches of rank 4 (unbatched: flat, gD, gH, gW) or rank 5 (batched: B, flat, gD, gH, gW) after layout handling. Any other rank cannot be a 3D patch grid, so it raises before reshaping.","triggerScenarios":"reconstruct_patches_3d reached via a rank-3 or rank-6 patches tensor, or 2D image patches (rank 4 but wrong semantics) passed with a 3-element size triggering the 3D branch.","commonSituations":"Calling the 3D path with 2D patches or vice versa; extra leading dims from a dataset batch; squeezing the wrong axis during preprocessing.","solutions":["Use the 2D reconstruct path for 2D patches (size length 2, rank-3/4 patches)","Ensure patches rank is 5 batched or 4 unbatched for 3D; add/remove batch axis with expand_dims/squeeze as needed","Print patches.shape right before the call and match it to (B, flat, gD, gH, gW)"],"exampleFix":"# before\nreconstruct_patches(patches_2d, size=(8,8), output_size=(16,28,28))\n\n# after\nreconstruct_patches(patches_2d, size=(8,8), output_size=(28,28))","handlingStrategy":"validation","validationCode":"assert len(patches.shape) in (4, 5), f'unexpected rank {len(patches.shape)}'\nassert len(size) == 3 and len(output_size) == 3","typeGuard":"def is_3d_patches(patches) -> bool:\n    return len(patches.shape) in (4, 5)","tryCatchPattern":null,"preventionTips":["Match 2D/3D call sites explicitly","Check rank after dataset batching/squeezing steps"],"tags":["keras","image","patches","rank-error","input-validation"],"backgroundTag":"tensor-rank-mismatch","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}