invoke-ai/InvokeAI · error

Cross-filesystem image move is not supported: {source} -> {d

Error message

Cross-filesystem image move is not supported: {source} -> {destination}

What it means

_assert_same_filesystem, called during preflight_moves, compares st_dev of the source directory and the nearest existing ancestor of the destination directory. If they differ, the move would cross filesystem boundaries (os.rename would fail with EXDEV), so the service raises ValueError('Cross-filesystem image move is not supported').

Source

Thrown at invokeai/app/services/image_moves/image_moves_default.py:876

                self._fsync_dir(path.parent)
        self.image_files.evict_cache_paths([old_path, new_path, old_thumbnail_path, new_thumbnail_path])
        self.mark_item_moved(job_id, image_name)

    def _remove_empty_parents(self, start: Path, root: Path) -> None:
        root = root.resolve()
        current = start.resolve()
        while current != root and current.is_relative_to(root):
            try:
                current.rmdir()
            except OSError:
                return
            current = current.parent

    def _assert_same_filesystem(self, source: Path, destination: Path) -> None:
        source_parent = source.parent
        destination_parent = self._nearest_existing_parent(destination.parent)
        if source_parent.stat().st_dev != destination_parent.stat().st_dev:
            raise ValueError(f"Cross-filesystem image move is not supported: {source} -> {destination}")

    def _nearest_existing_parent(self, path: Path) -> Path:
        current = path
        while not current.exists():
            if current.parent == current:
                raise FileNotFoundError(f"No existing parent found for {path}")
            current = current.parent
        return current

    def _fsync_file(self, path: Path) -> None:
        try:
            with path.open("rb") as file:
                os.fsync(file.fileno())
        except OSError as e:
            self._logger.debug("Unable to fsync file: %s: %s", path, e)

    def _fsync_dir(self, path: Path) -> None:
        try:

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Move the destination onto the same filesystem/mount as the source images directory (or vice versa).
  2. If using Docker/bind mounts, mount the destination path from the same volume as the images root.
  3. Replace a cross-device symlink with a same-filesystem directory or bind-mount the second disk into the tree so st_dev matches.
  4. Apply the subfolder strategy within the existing single filesystem instead of redirecting output to another device.

Example fix

// before
# source: /srv/invokeai/images (dev 8:1)
# destination: /mnt/nas/invokeai/images (dev 0:xx) -> ValueError
// after: keep both on one filesystem
ln -s /mnt/nas/invokeai /srv/invokeai/nas  # NO - still cross-device for moves
# instead mount nas under the same fs tree or move outputs dir onto /srv/invokeai
Defensive patterns

Strategy: validation

Validate before calling

import os
from pathlib import Path
def same_filesystem(src: Path, dst: Path) -> bool:
    p = dst
    while not p.exists():
        p = p.parent
    return os.stat(src.parent).st_dev == os.stat(p).st_dev

Type guard

def paths_share_device(a: Path, b: Path) -> bool:
    return a.stat().st_dev == b.stat().st_dev

Try / catch

try:
    service.preflight_moves(job_id)
except ValueError as e:
    if "Cross-filesystem image move" in str(e):
        # re-point destination onto the images filesystem or copy instead of move

Prevention

When it happens

Trigger: Running preflight_moves where the images root and the destination subfolder root live on different mounts — e.g. destination on a NFS/network volume, separate SSD/HDD, tmpfs, or Docker bind mount not sharing a filesystem with the source.

Common situations: Docker container with images dir and output dir on different mounts; NAS mounts (NFS/SMB); symlinking an output folder to another disk; WSL/Windows drive boundaries (/mnt/c vs ~).

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/5234b8e251715099. Report an issue: GitHub.