IceWhaleTech/CasaOS · error

mount failed

Error message

mount failed

What it means

Returned by Mount() in pkg/utils/httper/drive.go when the POST to the rclone REST endpoint /mount/mount completes but responds with a non-200 status. The CasaOS 'drive' layer is a thin HTTP wrapper over rclone's librclone/rest API, so a non-200 means rclone itself refused the mount (bad fs name, invalid options, or busy mount point). The error carries no detail because the code formats a static string and discards res.Body(), where rclone puts the actual reason.

Source

Thrown at pkg/utils/httper/drive.go:91

	json.Unmarshal(res.Body(), &result)
	for i := 0; i < len(result.MountPoints); i++ {
		result.MountPoints[i].Fs = result.MountPoints[i].Fs[:len(result.MountPoints[i].Fs)-1]
	}
	return result, err
}

func Mount(mountPoint string, fs string) error {
	res, err := NewRestyClient().R().SetFormData(map[string]string{
		"mountPoint": mountPoint,
		"fs":         fs,
		"mountOpt":   `{"AllowOther": true}`,
		"vfsOpt":     `{"CacheMode": 3}`,
	}).Post("/mount/mount")
	if err != nil {
		return err
	}
	if res.StatusCode() != 200 {
		return fmt.Errorf("mount failed")
	}
	logger.Info("mount then", zap.Any("res", res.Body()))
	return nil
}
func Unmount(mountPoint string) error {
	res, err := NewRestyClient().R().SetFormData(map[string]string{
		"mountPoint": mountPoint,
	}).Post("/mount/unmount")
	if err != nil {
		logger.Error("when unmount", zap.Error(err))
		return err
	}
	if res.StatusCode() != 200 {
		logger.Error("then unmount failed", zap.Any("res", res.Body()))
		return fmt.Errorf("unmount failed")
	}

	logger.Info("unmount then", zap.Any("res", res.Body()))

View on GitHub (pinned to 0d3b2f444e)

Solutions

  1. Check the rclone/drive service is running and healthy (systemctl status or the CasaOS service list) before calling Mount.
  2. Verify the fs config exists first with GetConfigByName(name) and that its type/backend parameters are valid.
  3. Confirm the mountPoint directory exists, is empty, and is not already mounted (mountpoint -q /mnt point).
  4. Ensure /etc/fuse.conf contains user_allow_other, since mountOpt sends AllowOther:true.
  5. Improve the error to include res.StatusCode() and string(res.Body()) so rclone's actual refusal reason is visible.

Example fix

// before
if res.StatusCode() != 200 {
    return fmt.Errorf("mount failed")
}

// after
if res.StatusCode() != 200 {
    return fmt.Errorf("mount failed: status=%d body=%s", res.StatusCode(), res.Body())
}
Defensive patterns

Strategy: validation

Validate before calling

// before calling Mount()
if _, err := httper.GetConfigByName(fs); err != nil {
    return fmt.Errorf("fs %q not configured: %w", fs, err)
}
if err := unix.Access(mountPoint, unix.W_OK); err != nil {
    return fmt.Errorf("mount point %q not writable: %w", mountPoint, err)
}
// reject an already-mounted point
if mnts, _ := os.ReadFile("/proc/mounts"); strings.Contains(string(mnts), " "+mountPoint+" ") {
    return fmt.Errorf("%s already mounted", mountPoint)
}

Try / catch

if err := httper.Mount(point, fs); err != nil {
    if strings.Contains(err.Error(), "mount failed") {
        // rclone refused: surface body detail, do not blind-retry (option errors are deterministic)
        logger.Error("rclone refused mount", zap.String("fs", fs), zap.Error(err))
        return err
    }
    // transport error: retry once after confirming the drive service is up
    return retryOnce(func() error { return httper.Mount(point, fs) })
}

Prevention

When it happens

Trigger: POST /mount/mount with form fields mountPoint, fs, mountOpt={"AllowOther":true}, vfsOpt={"CacheMode":3} against the rclone service returns non-200: (1) fs names a config that does not exist in rclone, (2) mountPoint path does not exist or is already mounted, (3) AllowOther requires user_allow_other in /etc/fuse.conf and it is disabled, (4) the rclone REST service is being restarted concurrently.

Common situations: Drive feature of CasaOS after a factory reset where rclone configs were wiped; upgrading rclone changed option names so previously valid mountOpt/vfsOpt JSON is rejected; running in a container without /dev/fuse or with FUSE not installed; leftover stale mount from a crashed process blocking the same mountPoint.

Related errors


AI-assisted analysis of IceWhaleTech/CasaOS@0d3b2f444e (2026-08-15). Data as JSON: /api/errors/b8a749dd4521af57. Report an issue: GitHub.