deepfakes/faceswap · error · FaceswapError

File '{file_path}' is not a valid video file

Error message

File '{file_path}' is not a valid video file

What it means

Raised by validate_video_file() in lib/video.py when the file exists but its extension is not in VIDEO_EXTENSIONS. This is a format check on the container extension only (no probing of actual content), so renaming a non-video file to .mp4 will pass this check but fail later at decode time.

Source

Thrown at lib/video.py:88

    Parameters
    ----------
    file_path
        The full path to the video file to validate

    Returns
    -------
    The full expanded video file path

    Raises
    ------
    FaceswapError
        If the given video file is not valid
    """
    file_path = os.path.expanduser(os.path.abspath(file_path))
    if not os.path.isfile(file_path):
        raise FaceswapError(f"Video file '{file_path}' does not exist")
    if os.path.splitext(file_path)[-1].lower() not in VIDEO_EXTENSIONS:
        raise FaceswapError(f"File '{file_path}' is not a valid video file")
    return file_path


# TODO look for instances of this and see if we can roll it into VideoInfo
def count_frames(filename, fast=False):
    """ Count the number of frames in a video file

    There is no guaranteed accurate way to get a count of video frames without iterating through
    a video and decoding every frame.

    :func:`count_frames` can return an accurate count (albeit fairly slowly) or a possibly less
    accurate count, depending on the :attr:`fast` parameter. A progress bar is displayed.

    Parameters
    ----------
    filename: str
        Full path to the video to return the frame count from.
    fast: bool, optional

View on GitHub (pinned to f530cb7508)

Solutions

  1. Confirm you passed a video container file (.mp4, .avi, .mkv, .mov, ...).
  2. If the content is video in an odd container, remux it: ffmpeg -i input.xyz -c copy output.mp4.
  3. If the content is images, pass the folder instead (that path does not go through validate_video_file).

Example fix

# before
faceswap extract -i frame_0001.jpg ...

# after
faceswap extract -i frames_folder/ ...  # images go as a folder
Defensive patterns

Strategy: validation

Validate before calling

from lib.video import VIDEO_EXTENSIONS
import os
assert os.path.splitext(video_path)[-1].lower() in VIDEO_EXTENSIONS, "not a video container"

Type guard

def has_video_extension(path: str, exts: set[str]) -> bool:
    return os.path.splitext(path)[-1].lower() in exts

Prevention

When it happens

Trigger: Passing an existing file whose extension is not a recognized video container (e.g. .jpg, .bin, .txt) to a code path that requires a video file.

Common situations: Pointing a video-consuming job at a subtitle, image, archive, or temporary file; renamed files that lost their extension; output of another tool written with an unexpected extension.

Related errors


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