{"record":{"id":"06b5df69f106f0a5","repo":"keras-team/keras","slug":"invalid-end-points-shape-expected-4-2-for-a-sin-06b5df","errorCode":null,"errorMessage":"Invalid end_points shape: expected (4,2) for a single image or (N,4,2) for a batch. Received shape: {end_points.shape}","messagePattern":"Invalid end_points shape: expected \\(4,2\\) for a single image or \\(N,4,2\\) for a batch\\. Received shape: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/ops/image.py","lineNumber":2189,"sourceCode":"            interpolation=self.interpolation,\n            fill_value=self.fill_value,\n            data_format=self.data_format,\n        )\n\n    def compute_output_spec(self, images, start_points, end_points):\n        if len(images.shape) not in (3, 4):\n            raise ValueError(\n                \"Invalid images rank: expected rank 3 (single image) \"\n                \"or rank 4 (batch of images). Received input with shape: \"\n                f\"images.shape={images.shape}\"\n            )\n        if start_points.shape[-2:] != (4, 2) or start_points.ndim not in (2, 3):\n            raise ValueError(\n                \"Invalid start_points shape: expected (4,2) for a single image\"\n                f\" or (N,4,2) for a batch. Received shape: {start_points.shape}\"\n            )\n        if end_points.shape[-2:] != (4, 2) or end_points.ndim not in (2, 3):\n            raise ValueError(\n                \"Invalid end_points shape: expected (4,2) for a single image\"\n                f\" or (N,4,2) for a batch. Received shape: {end_points.shape}\"\n            )\n        if start_points.shape != end_points.shape:\n            raise ValueError(\n                \"start_points and end_points must have the same shape.\"\n                f\" Received start_points.shape={start_points.shape}, \"\n                f\"end_points.shape={end_points.shape}\"\n            )\n        return KerasTensor(images.shape, dtype=images.dtype)\n\n\n@keras_export(\"keras.ops.image.perspective_transform\")\ndef perspective_transform(\n    images,\n    start_points,\n    end_points,\n    interpolation=\"bilinear\",","sourceCodeStart":2171,"sourceCodeEnd":2207,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/ops/image.py#L2171-L2207","documentation":"The perspective op requires end_points to mirror start_points: trailing dims (4, 2) with ndim 2 or 3. This fires when the destination corners are malformed even though start_points passed.","triggerScenarios":"perspective(img, start_points (4,2), end_points flat array of 8); end_points shaped (N, 2, 4) for a batch; only one of the two arrays reshaped after refactoring.","commonSituations":"Computing destination corners with a different code path (e.g. ordering corners via a polygon library) that yields a different layout; partially migrating legacy code.","solutions":["Apply the same reshape to end_points: (4, 2) or (N, 4, 2).","Derive both arrays from one helper so their layouts cannot diverge.","Add an assert end_points.shape[-2:] == (4, 2) before calling."],"exampleFix":"# before\nend_points = dst.reshape(-1)\n\n# after\nend_points = dst.reshape(4, 2)","handlingStrategy":"type-guard","validationCode":"import numpy as np\nep = np.asarray(end_points)\nif ep.ndim == 1 and ep.size == 8: ep = ep.reshape(4, 2)\nassert ep.ndim in (2, 3) and ep.shape[-2:] == (4, 2), ep.shape","typeGuard":"def valid_corner_points(p):\n    p = np.asarray(p)\n    return p.ndim in (2, 3) and tuple(p.shape[-2:]) == (4, 2)","tryCatchPattern":null,"preventionTips":["Generate start and end points from the same function signature.","Add a unit test asserting both arrays' shapes before training."],"tags":["keras","image","perspective","shape-validation"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}