deepfakes/faceswap · error · FaceswapError

Alignments file not found at {self._file}

Error message

Alignments file not found at {self._file}

What it means

LandmarkType.from_shape (lib/align/constants.py) maps a landmarks array's shape tuple to a LandmarkType enum member. Only (4,2), (51,2), (68,2), (98,2) and (26,3) are recognized; any other shape raises ValueError because Faceswap has no mean-face/template for it.

Source

Thrown at lib/align/alignments.py:589

            MaskCentering(alignments_dict, self._version),
            IdentityAndVideoMeta(alignments_dict, self._version))]
        if any(updates):
            self.update_version()
        return any(updates)

    def load(self) -> dict[str, AlignmentsEntry]:
        """Load the alignments data from the serialized alignments :attr:`file`.

        Populates :attr:`_version` with the alignment file's loaded version as well as returning
        the serialized data.

        Returns
        -------
        The loaded alignments data
        """
        logger.debug("Loading alignments")
        if not self.have_alignments_file:
            raise FaceswapError(f"Alignments file not found at {self._file}")

        logger.info("Reading alignments from: '%s'", self._file)
        data = self._serializer.load(self._file)
        meta = data.get("__meta__", {"version": 1.0})
        self._version = meta["version"]
        if self._version < 2.0:
            logger.error("This alignments file was generated with a very old legacy extraction "
                         "method.")
            logger.error("Updating these very old files is no longer supported.")
            logger.error("To update to a more recent, supported format, you should run the "
                         "alignments tool's 'extract' job with this file in Faceswap v2.3: "
                         "https://github.com/deepfakes/faceswap/releases/tag/v2.3.0")
            sys.exit(1)

        alignments = data["__data__"]
        if self._update_legacy(alignments):
            logger.info("Writing alignments to: '%s'", self._file)
            self._serializer.save(self._file, {"__meta__": {"version": self._version},

View on GitHub (pinned to f530cb7508)

Solutions

  1. Reshape/convert landmarks to one of the supported shapes before calling (e.g. arr.reshape(-1, 2) and verify the point count is 4/51/68/98 for 2D or 26 for 3D)
  2. For unsupported detectors, map landmarks down to 68 points (see MAP_2D_98 for an example of a mapping table) before creating DetectedFace data
  3. Validate the shape early and skip/log malformed frames instead of crashing the pipeline

Example fix

# before
lms = np.loadtxt("landmarks.txt")        # shape (136,)
ltype = LandmarkType.from_shape(lms.shape)  # ValueError

# after
lms = lms.reshape(-1, 2)                  # (68, 2)
if lms.shape in {(4, 2), (51, 2), (68, 2), (98, 2), (26, 3)}:
    ltype = LandmarkType.from_shape(lms.shape)
Defensive patterns

Strategy: validation

Validate before calling

import os

def alignments_ready(path):
    return os.path.isfile(path) and os.path.getsize(path) > 0

assert alignments_ready(my_path), f"missing alignments: {my_path}"

Try / catch

try:
    alignments = Alignments(folder, filename)
    alignments.load()
except FaceswapError as err:
    if "not found at" in str(err):
        raise SystemExit(f"Run extraction first to create {path}") from err
    raise

Prevention

When it happens

Trigger: Calling LandmarkType.from_shape(landmarks.shape) with a landmarks ndarray of any other shape, e.g. (5,2) from some external detector, (68,3) 3D landmarks, or a flattened (136,) array that was never reshaped to (68,2).

Common situations: Converting third-party detector outputs (MediaPipe 468-point, dlib 5-point, 3D landmarks) into Faceswap alignments; forgetting to reshape flat landmark vectors before passing them in; a corrupt/short landmarks row in a hand-edited alignments file.

Related errors


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