juicedata/juicefs · error

stat %s: %s

Error message

stat %s: %s

What it means

The `juicefs clone` command checks whether the destination path already exists by calling os.Stat. If Stat fails with an error that is NOT 'file does not exist' (e.g. permission denied on a parent directory, I/O error, or the path component is not a directory), the command cannot safely determine DST availability and wraps the raw error as "stat %s: %s".

Source

Thrown at cmd/clone.go:87

	if err != nil {
		return fmt.Errorf("abs of %s: %s", srcPath, err)
	}
	srcIno, err := utils.GetFileInode(srcPath)
	if err != nil {
		return fmt.Errorf("lookup inode for %s: %s", srcPath, err)
	}
	srcParentIno, err := utils.GetFileInode(filepath.Dir(srcAbsPath))
	if err != nil {
		return fmt.Errorf("lookup inode for %s: %s", filepath.Dir(srcAbsPath), err)
	}
	dst := ctx.Args().Get(1)
	if strings.HasSuffix(dst, string(filepath.Separator)) {
		dst = filepath.Join(dst, filepath.Base(srcPath))
	}
	if _, err := os.Stat(dst); err == nil {
		return fmt.Errorf("%s already exists", dst)
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("stat %s: %s", dst, err)
	}
	dstAbsPath, err := filepath.Abs(dst)
	if err != nil {
		return fmt.Errorf("abs of %s: %s", dst, err)
	}

	srcMp, err := findMountpoint(srcAbsPath)
	if err != nil {
		return err
	}
	dstMp, err := findMountpoint(filepath.Dir(dstAbsPath))
	if err != nil {
		return err
	}
	if srcMp != dstMp {
		return fmt.Errorf("the clone DST path should be at the same mount point as the SRC path")
	}
	if strings.HasPrefix(dstAbsPath, path.Clean(srcAbsPath)+"/") {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Check permissions on every existing component of DST (ls -ld on each parent) and grant search (+x) permission for the running user
  2. Verify each prefix of DST is a directory: run `stat` on each path component and fix or remove the non-directory component
  3. Check for symlink loops (`namei -l DST`) and fix the symlink
  4. If the mount is broken, remount the JuiceFS volume (`juicefs mount ...`) and retry
  5. As a workaround, pick a DST path in a directory you can stat and that does not exist yet

Example fix

// before
juicefs clone /mnt/jfs/a /mnt/jfs/otheruser/dir/x   # EACCES
// after
sudo chmod o+x /mnt/jfs/otheruser/dir
juicefs clone /mnt/jfs/a /mnt/jfs/otheruser/dir/x
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(dst); err != nil && !os.IsNotExist(err) {
    return fmt.Errorf("cannot stat destination %s: %w", dst, err)
}

Try / catch

err := sh.Run("juicefs", "clone", src, dst)
if strings.HasPrefix(err.Error(), "stat ") {
    // inspect DST path components: permissions / ENOTDIR
}

Prevention

When it happens

Trigger: Running `juicefs clone SRC DST` where os.Stat(DST) fails with an error other than ENOENT — e.g. a parent directory of DST lacks execute/search permission (EACCES), a path component is not a directory (ENOTDIR), the filesystem is inaccessible, or a symlink loop exists.

Common situations: DST parent directory owned by another user without +x permission; DST contains a non-directory component (e.g. cloning to /mnt/jfs/file1/sub/file when file1 is a regular file); stale NFS/FUSE mount returning I/O errors; SELinux/AppArmor blocking stat on the target.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/33aa7e4f88f25671. Report an issue: GitHub.