deepfakes/faceswap · error · FaceswapError

68 Point facial Landmarks are required for Warp-to-landmarks

Error message

68 Point facial Landmarks are required for Warp-to-landmarks. The face that failed was: '{filename}'

What it means

Warp-to-landmarks requires exactly 68-point 2D landmarks; after loading landmarks_xy from the face's embedded metadata, the shape is checked via LandmarkType.from_shape. Faces produced by landmark models with different point counts (e.g. 81-point or mask-extended outputs) fail this check with the offending filename.

Source

Thrown at lib/training/data/collate.py:167

        Returns
        -------
        landmarks
            The frame space landmarks for a face
        filename
            The name of the face image that we are loading landmarks for

        Raises
        ------
        FaceswapError
            If an invalid image is loaded or 68 point landmarks are not used
        """
        if "itxt" not in meta or "alignments" not in meta["itxt"]:
            raise FaceswapError(f"Invalid face image found. Aborting: '{filename}'")

        retval = np.array(meta["itxt"]["alignments"]["landmarks_xy"], dtype=np.float32)
        if LandmarkType.from_shape(retval.shape) != LandmarkType.LM_2D_68:
            raise FaceswapError("68 Point facial Landmarks are required for Warp-to-"
                                f"landmarks. The face that failed was: '{filename}'")
        return retval

    def _align_points(self, points: npt.NDArray[np.float32]) -> npt.NDArray[np.float32]:
        """Normalize and align the landmarks to model input size/coverage/offset

        points
        ------
        The (N, 68, 2) landmark points to align

        Returns
        -------
        The landmark points aligned to model input
        """
        mats = batch_umeyama(points[:, 17:], MEAN_FACE[LandmarkType.LM_2D_51], True)
        norm_lms = batch_transform(mats, points)

        rotation, translation = Batch3D.solve_pnp(norm_lms)

View on GitHub (pinned to f530cb7508)

Solutions

  1. Re-extract faces with the default 68-point aligner before warp-to-landmarks training.
  2. Remove non-conforming faces (named in the error) from the training set.
  3. Or switch the trainer's mask/warp method that does not require warp-to-landmarks.

Example fix

# before: faces extracted with non-68pt landmarks
# FaceswapError: 68 Point facial Landmarks are required...

# after: regenerate dataset with standard aligner
$ python faceswap.py extract -i /frames -o /faces -df s3fd -af fan
Defensive patterns

Strategy: validation

Validate before calling

from lib.image import read_image_meta
from lib.align.alignments import LandmarkType
import numpy as np

meta = read_image_meta(face_path)
lm = np.array(meta['itxt']['alignments']['landmarks_xy'])
assert LandmarkType.from_shape(lm.shape) == LandmarkType.LM_2D_68, \
    f'{face_path} does not have 68-point landmarks'

Type guard

def has_68_landmarks(face_path: str) -> bool:
    meta = read_image_meta(face_path)
    lm = np.array(meta['itxt']['alignments']['landmarks_xy'])
    return lm.shape[-2:] == (68, 2)

Try / catch

try:
    train(warp_to_landmarks=True)
except FaceswapError as err:
    if '68 Point' in str(err):
        drop_named_file_and_reindex_dataset()
    else:
        raise

Prevention

When it happens

Trigger: Training warp-to-landmarks on faces extracted with a non-68-point landmark plugin or converted alignments from another pipeline; mixed datasets where some faces carry different landmark formats.

Common situations: Changing detector/aligner settings between extraction and training; importing alignments from external tools; faceswap versions with alternate landmark output.

Related errors


AI-assisted analysis of deepfakes/faceswap@f530cb7508 (2026-08-15). Data as JSON: /api/errors/0a0cbf941bf744c8. Report an issue: GitHub.