{"record":{"id":"3f945ad90cf6e5b7","repo":"gitbutlerapp/gitbutler","slug":"failed-to-parse-url","errorCode":null,"errorMessage":"Failed to parse URL","messagePattern":"Failed to parse URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-api/src/open/mod.rs","lineNumber":612,"sourceCode":"            .with_context(|| format!(\"Failed to show '{path}' in Finder\"))?;\n    }\n\n    #[cfg(target_os = \"windows\")]\n    {\n        use std::process::Command;\n        Command::new(\"explorer\")\n            .arg(\"/select,\")\n            .arg(&path)\n            .status()\n            .with_context(|| format!(\"Failed to show '{path}' in Explorer\"))?;\n    }\n\n    #[cfg(target_os = \"linux\")]\n    {\n        // For directories, open the directory directly\n        if std::path::Path::new(&path).is_dir() {\n            open_that(\n                &Url::from_file_path(&path).map_err(|_| anyhow::anyhow!(\"Failed to parse URL\"))?,\n            )\n            .with_context(|| format!(\"Failed to open directory '{path}' in file manager\"))?;\n        } else {\n            // For files, try to open the parent directory\n            if let Some(parent) = std::path::Path::new(&path).parent() {\n                open_that(\n                    &Url::from_file_path(parent)\n                        .map_err(|_| anyhow::anyhow!(\"Failed to parse URL\"))?,\n                )\n                .with_context(|| {\n                    format!(\"Failed to open parent directory of '{path}' in file manager\",)\n                })?;\n            } else {\n                open_that(\n                    &Url::from_file_path(&path)\n                        .map_err(|_| anyhow::anyhow!(\"Failed to parse URL\"))?,\n                )\n                .with_context(|| format!(\"Failed to open '{path}' in file manager\"))?;","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-api/src/open/mod.rs#L594-L630","documentation":"On Linux, revealing a path in the file manager converts the filesystem path to a file:// URL with Url::from_file_path, which only accepts absolute paths. A relative path makes the conversion return Err, surfaced as this error (wrapped with the file-manager context message).","triggerScenarios":"Reveal-in-file-manager invoked with a repo-relative path that was never joined with the project workdir, or a path built by string concatenation that is not absolute.","commonSituations":"Callers passing repo-internal paths taken from diff output; paths assembled without the workdir prefix; un-canonicalized components like '.' or '..'.","solutions":["Join the relative path with the project workdir (or canonicalize it) before calling reveal","Validate that inputs are absolute at the API boundary and reject them early with a clearer message","Reuse the absolute paths already used for git operations"],"exampleFix":"// before: repo-relative path\nreveal_in_file_manager(relative_path)?;\n\n// after: absolute path from the project workdir\nlet abs = ctx.workdir()?.join(relative_path);\nreveal_in_file_manager(abs.to_string_lossy().as_ref())?;","handlingStrategy":"validation","validationCode":"let p = std::path::Path::new(&path);\nif !p.is_absolute() {\n    let abs = ctx.workdir()?.join(p);\n    // use `abs` for the reveal call\n}","typeGuard":"fn path_makes_file_url(p: &std::path::Path) -> bool {\n    p.is_absolute()\n}","tryCatchPattern":null,"preventionTips":["Always derive UI paths by joining with the project workdir","Canonicalize user-supplied paths before reveal/open actions","Reject relative paths at the boundary with an explicit validation error"],"tags":["open","file-manager","path","url","linux"],"backgroundTag":"relative-path-url-conversion","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}