{"record":{"id":"c5a85916650865a7","repo":"deepfakes/faceswap","slug":"landmark-based-masks-cannot-be-created-for-self","errorCode":null,"errorMessage":"Landmark based masks cannot be created for {self._landmark_type.name}","messagePattern":"Landmark based masks cannot be created for (.+?)","errorType":"exception","errorClass":"FaceswapError","httpStatus":null,"severity":"error","filePath":"lib/align/aligned_mask.py","lineNumber":510,"sourceCode":"    def __repr__(self) -> str:\n        \"\"\"Pretty print for logging\"\"\"\n        params = {f\"{k[1:]}\": format_array(v) if isinstance(v, np.ndarray) else v\n                  for k, v in self.__dict__.items()\n                  if k in (\"_area\", \"_landmark_type\", \"_landmarks\", \"_size\",\n                           \"_dilation\", \"_blur_kernel\", \"_blur_type\", \"blur_passes\")}\n        s_params = \", \".join(f\"{k}={repr(v)}\" for k, v in params.items())\n        return f\"{self.__class__.__name__}({s_params})\"\n\n    def _get_slices(self) -> list[slice] | list[list[slice]]:\n        \"\"\"Obtain the slices that will extract the points for the given area and landmark type\n\n        Returns\n        -------\n        The slices required to extract landmark points for creating a mask\n        \"\"\"\n        parts = LANDMARK_PARTS if self._area in (\"eye\", \"mouth\") else LANDMARK_MASK_PARTS\n        if self._landmark_type not in parts:\n            raise FaceswapError(\n                f\"Landmark based masks cannot be created for {self._landmark_type.name}\")\n\n        lm_parts = parts[self._landmark_type]\n        mapped = {\"mouth\": [\"mouth_outer\"],\n                  \"eye\": [\"right_eye\", \"left_eye\"],\n                  \"face\": list(lm_parts),\n                  \"face_extended\": list(lm_parts)}[self._area]\n\n        if not all(parts in lm_parts for parts in mapped):\n            raise FaceswapError(\n                f\"Landmark based masks cannot be created for {self._landmark_type.name}\")\n\n        if self._area in (\"eye\", \"mouth\"):\n            retval: list[slice] | list[list[slice]] = [slice(*lm_parts[v][:2]) for v in mapped]\n        else:\n            retval = [[slice(*p) for p in T.cast(list[tuple[int, int]], lm_parts[v])]\n                      for v in mapped]\n        logger.trace(\"[LM_MASK] area: '%s', slices: %s\",  # type:ignore[attr-defined]","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/deepfakes/faceswap/blob/f530cb7508ae670f6474f8a7d9c4df94705cf96b/lib/align/aligned_mask.py#L492-L528","documentation":"Raised by MaskAlignmentsFile._get_slices in lib/align/aligned_mask.py when the mask's landmark_type has no entry in the lookup dict for the requested area. For areas 'eye'/'mouth' the lookup is LANDMARK_PARTS (contains only LM_2D_68, LM_2D_98, LM_2D_4); for 'face'/'face_extended' it is LANDMARK_MASK_PARTS (contains only LM_2D_68 and LM_2D_98). Faceswap throws this because it has no slice definitions to build a landmark-based mask for that landmark type/area combination.","triggerScenarios":"Constructing MaskAlignmentsFile(area=..., landmark_type=..., landmarks=...) where area is 'face' or 'face_extended' and landmark_type is LM_2D_4, LM_2D_51 or LM_3D_26; or area is 'eye'/'mouth' with landmark_type LM_2D_51 or LM_3D_26. Happens at __init__ time (self.mask = self.generate_mask()).","commonSituations":"Running the mask plugin 'landmarks' with a detector that outputs 4-point landmarks (e.g. a 68-point pipeline replaced by a 4-point detector) then requesting a face mask; loading old alignments converted to LM_2D_51; requesting extended/face landmark masks after extraction with a minimal landmark set.","solutions":["Re-extract or re-detect faces with a detector/detector+2D-68 landmark pipeline (e.g. use the 68-point or 98-point landmark flavor) so landmark_type is LM_2D_68 or LM_2D_98","For eye/mouth masks, ensure alignments contain at least the eye/mouth landmark indices; switch to a different mask type (e.g. components, extended, dfl) which does not rely on LANDMARK_MASK_PARTS","Check the alignments file's landmark type with the alignments tool (e.g. 'alignments tool > spatial' or inspect DetectedFace.landmarks) to confirm which LandmarkType was stored"],"exampleFix":"# before\nmask = MaskAlignmentsFile(area=\"face\",\n                          landmark_type=LandmarkType.LM_2D_4,\n                          landmarks=face.landmarks,  # only 4 points\n                          size=128)\n\n# after\n# LM_2D_4 has no face-mask slices; use a supported type\nmask = MaskAlignmentsFile(area=\"face\",\n                          landmark_type=LandmarkType.LM_2D_68,\n                          landmarks=face.landmarks_68,\n                          size=128)","handlingStrategy":"validation","validationCode":"from lib.align.constants import LandmarkType, LANDMARK_PARTS, LANDMARK_MASK_PARTS\n\ndef can_build_mask(area, lmk_type):\n    parts = LANDMARK_PARTS if area in (\"eye\", \"mouth\") else LANDMARK_MASK_PARTS\n    return lmk_type in parts","typeGuard":"from lib.align.constants import LandmarkType, LANDMARK_PARTS, LANDMARK_MASK_PARTS\n\ndef maskable_landmark_type(area: str, lmk: LandmarkType) -> bool:\n    \"\"\"True if MaskAlignmentsFile supports (area, lmk) combination.\"\"\"\n    table = LANDMARK_PARTS if area in (\"eye\", \"mouth\") else LANDMARK_MASK_PARTS\n    return lmk in table","tryCatchPattern":"try:\n    mask = MaskAlignmentsFile(area=area, landmark_type=lmk_type, landmarks=lms, size=128)\nexcept FaceswapError:\n    logger.warning(\"mask unsupported for %s/%s, skipping\", area, lmk_type.name)\n    mask = None","preventionTips":["Check LandmarkType against LANDMARK_PARTS/LANDMARK_MASK_PARTS before building masks","Standardize pipelines on 68- or 98-point landmark extraction","Fail fast on 4-point alignments before requesting eye/mouth/face landmark masks"],"tags":["faceswap","landmarks","mask","validation"],"backgroundTag":null,"analyzedSha":"f530cb7508ae670f6474f8a7d9c4df94705cf96b","analyzedAt":"2026-08-15T02:59:26.626Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}