{"record":{"id":"24c986244c21cbd5","repo":"deepfakes/faceswap","slug":"the-given-shape-shape-is-not-valid-valid-shapes","errorCode":null,"errorMessage":"The given shape {shape} is not valid. Valid shapes: {list(shapes)}","messagePattern":"The given shape (.+?) is not valid\\. Valid shapes: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/align/constants.py","lineNumber":47,"sourceCode":"        shape\n            The shape to get the landmark type for\n\n        Returns\n        -------\n        The enum for the given shape\n\n        Raises\n        ------\n        ValueError\n            If the requested shape is not valid\n        \"\"\"\n        shapes: dict[tuple[int, int], LandmarkType] = {(4, 2): cls.LM_2D_4,\n                                                       (51, 2): cls.LM_2D_51,\n                                                       (68, 2): cls.LM_2D_68,\n                                                       (98, 2): cls.LM_2D_98,\n                                                       (26, 3): cls.LM_3D_26}\n        if shape not in shapes:\n            raise ValueError(f\"The given shape {shape} is not valid. Valid shapes: {list(shapes)}\")\n        return shapes[shape]\n\n\nEXTRACT_RATIOS: dict[CenteringType, float] = {\"legacy\": 0.375, \"face\": 0.5, \"head\": 0.625}\n\"\"\"The amount of padding applied to each centering type when generating aligned faces\"\"\"\n\nMEAN_FACE: dict[LandmarkType, np.ndarray] = {\n    LandmarkType.LM_2D_4: np.array(\n        [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]),  # Clockwise from TL\n    LandmarkType.LM_2D_51: np.array([\n        [0.010086, 0.106454], [0.085135, 0.038915], [0.191003, 0.018748], [0.300643, 0.034489],\n        [0.403270, 0.077391], [0.596729, 0.077391], [0.699356, 0.034489], [0.808997, 0.018748],\n        [0.914864, 0.038915], [0.989913, 0.106454], [0.500000, 0.203352], [0.500000, 0.307009],\n        [0.500000, 0.409805], [0.500000, 0.515625], [0.376753, 0.587326], [0.435909, 0.609345],\n        [0.500000, 0.628106], [0.564090, 0.609345], [0.623246, 0.587326], [0.131610, 0.216423],\n        [0.196995, 0.178758], [0.275698, 0.179852], [0.344479, 0.231733], [0.270791, 0.245099],\n        [0.192616, 0.244077], [0.655520, 0.231733], [0.724301, 0.179852], [0.803005, 0.178758],\n        [0.868389, 0.216423], [0.807383, 0.244077], [0.729208, 0.245099], [0.264022, 0.780233],","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/deepfakes/faceswap/blob/f530cb7508ae670f6474f8a7d9c4df94705cf96b/lib/align/constants.py#L29-L65","documentation":"Raised in the dataclass from_dict loader mixin (lib/align/objects.py, used by AlignedFace/Alignment/DetectedFace serialized data) when the incoming dict contains keys that are not fields of the dataclass. It guards against schema drift between the serialized alignments file and the current code.","triggerScenarios":"Calling cls.from_dict(data) (e.g. Alignment.from_dict) where data was produced by a different/older Faceswap version with renamed or extra fields, or a hand-crafted dict with a typo'd key like 'lmk_type' instead of 'landmark_type'.","commonSituations":"Loading alignments files written by a newer Faceswap into an older checkout (or vice versa); manually editing alignments JSON/pickle; a plugin writing non-schema keys into alignment entries.","solutions":["Regenerate the alignments file with the Faceswap version you are running (re-run extraction)","Update/checkout the Faceswap version that matches the file's '__meta__' version field and use its migration path (alignments tool 'extract' job)","If hand-building dicts, remove unknown keys: {k: v for k, v in data.items() if k in field_names}"],"exampleFix":"# before\nentry = {\"x\": 1, \"y\": 2, \"landmarks_xy\": pts, \"bogus_key\": 0}\naligned = Alignment.from_dict(entry)  # ValueError: bogus_key not a field\n\n# after\nfrom dataclasses import fields\nvalid = {f.name for f in fields(Alignment)}\naligned = Alignment.from_dict({k: v for k, v in entry.items() if k in valid})","handlingStrategy":"type-guard","validationCode":"import cv2, numpy as np\n\nVALID = {(4, 2), (51, 2), (68, 2), (98, 2), (26, 3)}\n\ndef load_landmarks(path):\n    arr = np.loadtxt(path)\n    if arr.ndim == 1:\n        arr = arr.reshape(-1, arr.shape[-1] if arr.ndim else 2) if arr.size else arr\n        arr = arr.reshape(-1, 2) if arr.size and arr.shape[0] not in (26,) else arr\n    if tuple(arr.shape) not in VALID:\n        raise ValueError(f\"unsupported landmarks shape {arr.shape}; expected one of {VALID}\")\n    return arr","typeGuard":"from lib.align.constants import LandmarkType\n\n_VALID_SHAPES = {(4, 2), (51, 2), (68, 2), (98, 2), (26, 3)}\n\ndef is_supported_landmarks(arr: \"np.ndarray\") -> bool:\n    \"\"\"Narrow arr to shapes LandmarkType.from_shape accepts.\"\"\"\n    return tuple(arr.shape) in _VALID_SHAPES","tryCatchPattern":"try:\n    ltype = LandmarkType.from_shape(lms.shape)\nexcept ValueError:\n    logger.warning(\"skipping frame with landmarks shape %s\", lms.shape)\n    continue","preventionTips":["Reshape flat landmark vectors to (n,2)/(n,3) immediately on load","Whitelist-check point counts (4/51/68/98/26) at ingestion from external detectors","Add unit fixtures asserting landmark shapes before running pipelines"],"tags":["faceswap","alignments","serialization","dataclass","schema"],"backgroundTag":null,"analyzedSha":"f530cb7508ae670f6474f8a7d9c4df94705cf96b","analyzedAt":"2026-08-15T02:59:26.626Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}