{"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":null,"httpStatus":null,"severity":"error","filePath":"yazi-fs/src/fns.rs","lineNumber":113,"sourceCode":"\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":95,"sourceCodeEnd":129,"githubUrl":"https://github.com/sxyazi/yazi/blob/8ebf930f1796ae2076b7d6b0c5e93a1002c18134/yazi-fs/src/fns.rs#L95-L129","documentation":"create_owned_dir_blocking creates a directory intended to be private to the current user. After creating it, it stats the directory and rejects it with PermissionDenied if st_uid differs from the current uid, then enforces mode 0o700 via fchmod. The error protects against pre-existing directories planted by another user (e.g. a symlink/hardening attack or leftover dirs from a different account).","triggerScenarios":"Creating a config/cache/data directory whose path already exists and is owned by a different uid — e.g. the app was previously run as root (sudo), leaving ~/.config/yazi owned by root, and now a normal user runs the deserializer's over-hook / create_owned_dir.","commonSituations":"Running yazi once with sudo; Docker containers that started as root then switched user; NFS/shared filesystems where uid mapping differs; an admin pre-created the directory under a service account.","solutions":["chown the directory back to the current user (sudo chown -R $USER:$USER <dir>) or simply remove it and let the app recreate it.","Avoid running the application with sudo; if root is needed initially, fix ownership afterwards.","Check the parent path in the error message for stale root-owned state in ~/.cache, ~/.config, or ~/.local/share."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// shell: verify ownership before running\n[ \"$(stat -c %u ~/.config/yazi 2>/dev/null)\" = \"$(id -u)\" ] || echo \"fix ownership: sudo chown -R $(id -u):$(id -g) ~/.config/yazi\"","typeGuard":null,"tryCatchPattern":"if let Err(e) = create_owned_dir(&dir).await {\n    if e.kind() == std::io::ErrorKind::PermissionDenied {\n        eprintln!(\"{} is owned by another user; run: sudo chown -R $USER <dir>\", dir.display());\n    }\n    return Err(e.into());\n}","preventionTips":["Never run desktop apps with sudo.","After running as root, chown -R $USER your config/cache dirs.","Check ownership of XDG dirs after switching users or containers."],"tags":["permissions","ownership","unix","security"],"backgroundTag":"directory-ownership-mismatch","analyzedSha":"8ebf930f1796ae2076b7d6b0c5e93a1002c18134","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}