{"record":{"id":"dff52a1bcf224813","repo":"sxyazi/yazi","slug":"paths-must-be-both-absolute-or-both-relative-fro","errorCode":null,"errorMessage":"Paths must be both absolute or both relative: {from:?} and {to:?}","messagePattern":"Paths must be both absolute or both relative: (.+?) and (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"yazi-fs/src/path/relative.rs","lineNumber":21,"sourceCode":"use anyhow::{Result, bail};\nuse yazi_shared::path::{PathBufDyn, PathCow, PathDyn, PathLike};\n\npub fn path_relative_to<'a, 'b, P, Q>(from: P, to: Q) -> Result<PathCow<'b>>\nwhere\n\tP: Into<PathCow<'a>>,\n\tQ: Into<PathCow<'b>>,\n{\n\tpath_relative_to_impl(from.into(), to.into())\n}\n\nfn path_relative_to_impl<'a>(from: PathCow<'_>, to: PathCow<'a>) -> Result<PathCow<'a>> {\n\tuse yazi_shared::path::Component::*;\n\n\tif from.is_absolute() != to.is_absolute() {\n\t\treturn if to.is_absolute() {\n\t\t\tOk(to)\n\t\t} else {\n\t\t\tbail!(\"Paths must be both absolute or both relative: {from:?} and {to:?}\");\n\t\t};\n\t}\n\n\tif from == to {\n\t\treturn Ok(PathDyn::with_str(from.kind(), \".\").into());\n\t}\n\n\tlet (mut f_it, mut t_it) = (from.components(), to.components());\n\tlet (f_head, t_head) = loop {\n\t\tmatch (f_it.next(), t_it.next()) {\n\t\t\t(Some(RootDir), Some(RootDir)) => {}\n\t\t\t(Some(Prefix(a)), Some(Prefix(b))) if path_prefix_eq(a, b) => {}\n\t\t\t(Some(Prefix(_) | RootDir), _) | (_, Some(Prefix(_) | RootDir)) => {\n\t\t\t\treturn Ok(to);\n\t\t\t}\n\t\t\t(None, None) => break (None, None),\n\t\t\t(a, b) if a != b => break (a, b),\n\t\t\t_ => (),","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/sxyazi/yazi/blob/5f901b886b14de1f17460b6e52e9de5d67f8aba9/yazi-fs/src/path/relative.rs#L3-L39","documentation":"`path_relative_to_impl` computes a relative path from `from` to `to`, but only when both share the same absoluteness. If `from` is relative and `to` is absolute (the asymmetric case), the operation is ill-defined and the code bails with this message (an absolute `to` is returned directly instead). It protects callers from meaningless cross-base relativization.","triggerScenarios":"Calling `path_relative_to(from, to)` where `from.is_absolute() != to.is_absolute()` and `to` is relative — e.g. `path_relative_to(\"/base/dir\", \"file.txt\")`.","commonSituations":"Mixing a cwd-derived relative path with a config-supplied absolute URL (or vice versa); passing user input paths that were never canonicalized; plugin/Lua code passing an absolute target into an API expecting relative inputs.","solutions":["Canonicalize both inputs to the same form before calling: turn the relative path into an absolute one (join with cwd) or make `to` relative.","If `to` is absolute, no fix is needed — the function already returns it unchanged.","Check `Path::is_absolute()` on both arguments and branch in caller code."],"exampleFix":"// before\nlet rel = path_relative_to(\"/base\", \"child/file\").unwrap();\n// after\nlet to_abs = std::env::current_dir().unwrap().join(\"child/file\");\nlet rel = path_relative_to(\"/base\", to_abs).unwrap();","handlingStrategy":"validation","validationCode":"if from.is_absolute() != to.is_absolute() && !to.is_absolute() {\n    panic!(\"both paths must be absolute or both relative\");\n}","typeGuard":"fn can_relativize(from: &Path, to: &Path) -> bool {\n    from.is_absolute() == to.is_absolute() || to.is_absolute()\n}","tryCatchPattern":"let rel = match path_relative_to(from, to) {\n    Ok(p) => p,\n    Err(e) if e.to_string().starts_with(\"Paths must be both absolute\") => {\n        to.to_path_buf() // absolute target returned as-is\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Canonicalize all paths to absolute form (join with cwd) before relativizing.","Assert argument absoluteness in tests around path computation helpers.","Never mix config-supplied absolute URLs with cwd-derived relative paths without normalizing."],"tags":["path","relative-path","validation"],"backgroundTag":"mixed-absolute-relative-paths","analyzedSha":"5f901b886b14de1f17460b6e52e9de5d67f8aba9","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}