{"record":{"id":"be13377a98ab2951","repo":"sxyazi/yazi","slug":"directory-is-owned-by-uid-but-current-uid","errorCode":null,"errorMessage":"directory {:?} is owned by uid {} but current uid is {}","messagePattern":"directory (.+?) is owned by uid (.+?) but current uid is (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/fns.rs","lineNumber":108,"sourceCode":"\t{\n\t\tuse std::{fs::{DirBuilder, OpenOptions}, mem, os::unix::{fs::{DirBuilderExt, OpenOptionsExt}, io::AsRawFd}};\n\n\t\tuse libc::{O_DIRECTORY, O_NOFOLLOW};\n\t\tuse uzers::Users;\n\t\tuse yazi_shared::USERS_CACHE;\n\n\t\tDirBuilder::new().mode(0o700).recursive(true).create(p)?;\n\t\tlet dir = OpenOptions::new().read(true).custom_flags(O_DIRECTORY | O_NOFOLLOW).open(p)?;\n\n\t\tlet mut stat: libc::stat = unsafe { mem::zeroed() };\n\t\tif unsafe { libc::fstat(dir.as_raw_fd(), &mut stat) } != 0 {\n\t\t\treturn Err(io::Error::last_os_error());\n\t\t}\n\n\t\t// Reject directories not owned by the current user.\n\t\tlet uid = USERS_CACHE.get_current_uid();\n\t\tif stat.st_uid != uid {\n\t\t\treturn Err(io::Error::new(\n\t\t\t\tio::ErrorKind::PermissionDenied,\n\t\t\t\tformat!(\"directory {:?} is owned by uid {} but current uid is {}\", p, stat.st_uid, uid),\n\t\t\t));\n\t\t}\n\n\t\t// Enforce mode 0o700 via the fd.\n\t\tif unsafe { libc::fchmod(dir.as_raw_fd(), 0o700) } != 0 {\n\t\t\treturn Err(io::Error::last_os_error());\n\t\t}\n\n\t\tOk(())\n\t}\n\t#[cfg(not(unix))]\n\t{\n\t\tstd::fs::DirBuilder::new().recursive(true).create(p)\n\t}\n}\n","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/fns.rs#L90-L126","documentation":"`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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["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.","Fix ownership instead of deleting: `sudo chown -R $(id -u):$(id -g) <dir>`.","Always run the app as the same user that owns its runtime dirs; never launch it with `sudo` for normal use.","Point the runtime dir at a per-user location (e.g. under `$XDG_RUNTIME_DIR`) that cannot be pre-created by others."],"exampleFix":"# before\n# dir was created by root earlier; app now runs as uid 1000 -> PermissionDenied\n\n# after\nsudo rm -rf /run/user/1000/yazi\n# restart the app; it recreates the dir owned by uid 1000 with mode 0700","handlingStrategy":"validation","validationCode":"use uzers::Users;\nuse yazi_shared::USERS_CACHE;\n\nfn owned_by_current_user(p: &std::path::Path) -> std::io::Result<bool> {\n    use std::os::unix::fs::MetadataExt;\n    let uid = USERS_CACHE.get_current_uid();\n    Ok(std::fs::metadata(p)?.uid() == uid)\n}\n\nif !owned_by_current_user(p)? { /* fix ownership before create_owned_dir */ }","typeGuard":null,"tryCatchPattern":"match create_owned_dir(p).await {\n    Ok(()) => {}\n    Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {\n        // surface path + current uid; instruct chown/rm of the foreign-owned dir\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never run the app under sudo/root for normal use; runtime dirs then become root-owned.","Keep per-process state under $XDG_RUNTIME_DIR, which is uid-scoped by design.","On first launch failure with PermissionDenied, check `stat -c %u <dir>` before retrying."],"tags":["unix","permissions","uid","security","runtime-dir"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}