{"record":{"id":"e5714d81286f36de","repo":"BigPizzaV3/CodexPlusPlus","slug":"expected-an-absolute-local-path","errorCode":null,"errorMessage":"Expected an absolute local path","messagePattern":"Expected an absolute local path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":110,"sourceCode":"struct Journal {\n    schema: u32,\n    original_sha: String,\n    candidate_sha: String,\n    modified_secs: u64,\n    modified_nanos: u32,\n}\n\nfn sha(bytes: &[u8]) -> String {\n    format!(\"{:x}\", Sha256::digest(bytes))\n}\n\nfn key_valid(key: &str) -> bool {\n    key.len() == 16 && key.bytes().all(|b| b.is_ascii_hexdigit())\n}\n\n// Reject junctions as well as symlinks, including in parent directories.\nfn plain_path(path: &Path) -> Result<()> {\n    ensure!(path.is_absolute(), \"Expected an absolute local path\");\n    for ancestor in path.ancestors() {\n        if let Ok(meta) = fs::symlink_metadata(ancestor) {\n            ensure!(\n                !meta.file_type().is_symlink(),\n                \"Linked paths are unsupported\"\n            );\n            #[cfg(windows)]\n            {\n                use std::os::windows::fs::MetadataExt;\n                ensure!(\n                    meta.file_attributes() & 0x400 == 0,\n                    \"Reparse paths are unsupported\"\n                );\n            }\n        }\n    }\n    ensure!(\n        !path","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L92-L128","documentation":"plain_path in native_browser.rs enforces the path-safety contract for native browser roots and pinned paths: the path must be absolute. Relative paths cannot be safely canonicalized/pinned across processes, so this check runs first before the symlink/junction checks.","triggerScenarios":"Any of plain_path's callers — pin_parents, selected_key, discover, prepare, restore_all, reconcile_contract — receiving a relative path from config, CLI input, or environment-derived values and passing it into plain_path.","commonSituations":"Config values like `runtime_root = \"browser-data\"` without a drive/absolute prefix; paths built via string concatenation without std::env::current_dir; variables that resolve to empty/relative values on the machine.","solutions":["Make the configured path absolute (include drive letter, e.g. C:\\\\...) in config or arguments","Canonicalize relative input before calling: std::fs::canonicalize or dunce::canonicalize on the base dir then join","Reject/repair empty or relative env-derived values at config load time","Join relative user input onto an absolute base dir before invoking the browser APIs"],"exampleFix":"// before\nplain_path(Path::new(\"browser-data/runtime\"))?;\n// after\nlet abs = std::path::absolute(base_dir.join(\"browser-data/runtime\"))?;\nplain_path(&abs)?;","handlingStrategy":"validation","validationCode":"fn ensure_absolute(p: &std::path::Path) -> bool {\n    p.is_absolute()\n}","typeGuard":"fn is_absolute_path(p: &Path) -> bool { p.is_absolute() }","tryCatchPattern":"match plain_path(p) {\n    Err(e) if e.to_string().contains(\"absolute local path\") => {\n        let abs = std::path::absolute(p)?;\n        plain_path(&abs)?;\n    }\n    other => other?,\n}","preventionTips":["Store absolute paths in config; expand env vars at load time","Never build paths via raw string concatenation without a base dir","Validate path absoluteness at configuration ingest, not at use time"],"tags":["rust","path","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}