sxyazi/yazi · error · io::Error

directory {:?} is owned by uid {} but current uid is {}

Error message

directory {:?} is owned by uid {} but current uid is {}

What it means

`create_owned_dir_blocking` (yazi-fs/src/fns.rs:108) creates a directory with mode 0o700, opens it with `O_DIRECTORY|O_NOFOLLOW`, `fstat`s it, and rejects it when `st_uid` differs from the current effective uid (`ErrorKind::PermissionDenied`). This is a security check: a 0o700 private dir owned by someone else would let that owner read data the current process writes there.

Source

Thrown at yazi-fs/src/fns.rs:108

	{
		use std::{fs::{DirBuilder, OpenOptions}, mem, os::unix::{fs::{DirBuilderExt, OpenOptionsExt}, io::AsRawFd}};

		use libc::{O_DIRECTORY, O_NOFOLLOW};
		use uzers::Users;
		use yazi_shared::USERS_CACHE;

		DirBuilder::new().mode(0o700).recursive(true).create(p)?;
		let dir = OpenOptions::new().read(true).custom_flags(O_DIRECTORY | O_NOFOLLOW).open(p)?;

		let mut stat: libc::stat = unsafe { mem::zeroed() };
		if unsafe { libc::fstat(dir.as_raw_fd(), &mut stat) } != 0 {
			return Err(io::Error::last_os_error());
		}

		// Reject directories not owned by the current user.
		let uid = USERS_CACHE.get_current_uid();
		if stat.st_uid != uid {
			return Err(io::Error::new(
				io::ErrorKind::PermissionDenied,
				format!("directory {:?} is owned by uid {} but current uid is {}", p, stat.st_uid, uid),
			));
		}

		// Enforce mode 0o700 via the fd.
		if unsafe { libc::fchmod(dir.as_raw_fd(), 0o700) } != 0 {
			return Err(io::Error::last_os_error());
		}

		Ok(())
	}
	#[cfg(not(unix))]
	{
		std::fs::DirBuilder::new().recursive(true).create(p)
	}
}

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. Remove the offending directory and let the current user recreate it: `sudo rm -rf /run/user/1000/<dir>` (or the path shown in the message), then retry.
  2. Fix ownership instead of deleting: `sudo chown -R $(id -u):$(id -g) <dir>`.
  3. Always run the app as the same user that owns its runtime dirs; never launch it with `sudo` for normal use.
  4. Point the runtime dir at a per-user location (e.g. under `$XDG_RUNTIME_DIR`) that cannot be pre-created by others.

Example fix

# before
# dir was created by root earlier; app now runs as uid 1000 -> PermissionDenied

# after
sudo rm -rf /run/user/1000/yazi
# restart the app; it recreates the dir owned by uid 1000 with mode 0700
Defensive patterns

Strategy: validation

Validate before calling

use uzers::Users;
use yazi_shared::USERS_CACHE;

fn owned_by_current_user(p: &std::path::Path) -> std::io::Result<bool> {
    use std::os::unix::fs::MetadataExt;
    let uid = USERS_CACHE.get_current_uid();
    Ok(std::fs::metadata(p)?.uid() == uid)
}

if !owned_by_current_user(p)? { /* fix ownership before create_owned_dir */ }

Try / catch

match create_owned_dir(p).await {
    Ok(()) => {}
    Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {
        // surface path + current uid; instruct chown/rm of the foreign-owned dir
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The directory already exists (pre-created by root, another user, or an earlier run under a different uid) and `create` succeeds as a no-op; the subsequent fstat then finds a foreign owner. Typical for runtime/socket/cache dirs under `/run/user/<uid>` or `$XDG_RUNTIME_DIR`.

Common situations: Running yazi once under `sudo` and again as the normal user (root-owned dir left behind); container/user-namespace builds where uid mapping shifts; a shared or restored home where the runtime dir kept its old owner.

Related errors


AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16). Data as JSON: /api/errors/be13377a98ab2951. Report an issue: GitHub.