juicedata/juicefs · error

open control file for [%d:%s]: %w

Error message

open control file for [%d:%s]: %w

What it means

doCompact sends a compact request by writing to the .control file exposed by the JuiceFS FUSE mount at the given path. openController opens .control under the mount point; if the open fails (path not on a JuiceFS mount, mount dead, permission denied), the error is wrapped as "open control file for [%d:%s]: %w" with the inode and path.

Source

Thrown at cmd/compact.go:93

			continue
		}
		inode := meta.Ino(inodeNo)

		if !inode.IsValid() {
			logger.Fatalf("inode numbe %d not valid", inode)
		}

		if err = doCompact(inode, path, uint16(coCnt)); err != nil {
			logger.Error(err)
		}
	}
	return nil
}

func doCompact(inode meta.Ino, path string, coCnt uint16) error {
	f, err := openController(path)
	if err != nil {
		return fmt.Errorf("open control file for [%d:%s]: %w", inode, path, err)
	}
	defer f.Close()

	headerLen, bodyLen := uint32(8), uint32(8+2)
	wb := utils.NewBuffer(headerLen + bodyLen)
	wb.Put32(meta.CompactPath)
	wb.Put32(bodyLen)
	wb.Put64(uint64(inode))
	wb.Put16(coCnt)

	_, err = f.Write(wb.Bytes())
	if err != nil {
		logger.Fatalf("write message: %s", err)
	}

	progress := utils.NewProgress(false)
	bar := progress.AddCountBar("Compacted chunks", 0)
	_, errno := readProgress(f, func(totalChunks, currChunks uint64) {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Confirm the path is on a live JuiceFS mount: `ls <mountpoint>/.control` and `mount | grep juicefs`; remount if absent
  2. Use the mount point path (not a subpath on another filesystem) as the compact argument
  3. Run with sufficient privileges (root or the mounting user) to open .control
  4. Check mount daemon logs (`juicefs mount` log) for the reason the FUSE connection is gone, fix, and remount

Example fix

// before
juicefs compact /tmp/data  # open control file for [2:/tmp/data]: ...
// after
juicefs mount redis://127.0.0.1:6379/1 /mnt/jfs
juicefs compact /mnt/jfs/data
Defensive patterns

Strategy: try-catch

Validate before calling

ctrl := filepath.Join(mountpoint, ".control")
if _, err := os.OpenFile(ctrl, os.O_WRONLY, 0); err != nil {
    return fmt.Errorf("control file %s not writable: %w", ctrl, err)
}

Try / catch

if err := runCompact(path); strings.Contains(err.Error(), "open control file for") {
    remount(mountpoint); err = runCompact(path)
}

Prevention

When it happens

Trigger: Running `juicefs compact <path>` where <path> is not inside a mounted JuiceFS volume, the FUSE mount has crashed/unmounted, or the user lacks permission to open .control in the mount root.

Common situations: Compact invoked with a typo'd or local-filesystem path; mount daemon exited between listing inodes and compacting; running as non-root on a mount where .control is restricted; autofs unmounted the volume before the command ran.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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