Watch at EaseStories. Answers. Perspective.

Technology · PRACTICAL GUIDE

“Invalid cross-device link”? Prove the syscall before copying or deleting

EXDEV can mean a cross-mount rename—or a path-resolution policy refusal. Capture the caller and syscall, compare mount IDs, then choose a transfer contract that keeps the source until the destination is verified.

Original technical diagram: EXDEV evidence boundary.
Original Watch at Ease illustration: prove which syscall returned EXDEV and why. Watch at Ease

The words “Invalid cross-device link” name EXDEV, not a complete diagnosis. rename() returns it when source and destination are on different mounted filesystems, while openat2() can return the same errno when a containment or no-cross-mount rule rejects path resolution.

A cross-filesystem move is normally copy plus source removal, not one atomic rename. That difference must be visible in automation, recovery and rollback.

Freeze the exact failure boundary

Record the program, arguments, working directory, namespace or container, source and destination as supplied, resolved paths, errno and timestamps. Preserve the first failure before wrappers retry it.

Trace only enough to name the failing syscall and paths. The same message from rename(), link(), openat2() or an application wrapper does not authorize the same repair.

Compare mount identity and path resolution

Compare the mount ID and filesystem visible to the actual process, not a host-side drive label. Bind mounts, containers and repeated mounts can make two similar paths belong to different rename domains.

Check destination-parent existence, type, permissions, free space and collision policy separately. EXDEV does not prove those other requirements are satisfied.

Do not confuse rename with openat2 policy

For rename(), different mount points explain EXDEV. For openat2(), inspect resolve flags and whether an absolute path, symlink, .. component or mount crossing violates the caller's intended containment.

Do not disable a security boundary merely to silence the errno. Fix the path contract or use a reviewed destination inside the allowed root when policy caused the failure.

Design a safe cross-filesystem fallback

If the move truly crosses filesystems, create a temporary destination on the destination filesystem, copy data and required metadata, flush according to the durability contract, then rename the temporary entry into place there.

Handle destination collisions explicitly. On any copy or verification failure, keep the source and remove or quarantine the partial destination; never report an atomic move.

Verify the destination before removing the source

Compare size and a suitable content digest, then verify required ownership, mode, timestamps, links, ACLs or extended attributes for the data class. Directory trees also need a complete manifest and error count.

Only after destination acceptance should the source be removed. Record whether the operation was a rename or a copy-and-remove so recovery can identify which side is authoritative.

Original technical diagram: Cross-filesystem move decision.
Original Watch at Ease illustration: separate atomic rename from a verified copy-and-remove workflow. Watch at Ease