{"record":{"id":"19b7e001a4f0aa47","repo":"gitbutlerapp/gitbutler","slug":"failed-to-get-app-bundle-name","errorCode":null,"errorMessage":"Failed to get app bundle name","messagePattern":"Failed to get app bundle name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":73,"sourceCode":"    success(\"Download completed successfully\");\n\n    verify_signature(&tarball_path, &platform_info.signature, temp_dir.path())?;\n\n    info(\"Extracting archive...\");\n    let app_dir = extract_tarball(&tarball_path, temp_dir.path())?;\n    success(\"Archive extracted successfully\");\n\n    verify_app_structure(&app_dir)?;\n\n    install_app(&app_dir, &config.home_dir, channel)?;\n\n    Ok(())\n}\n\npub(crate) fn install_app(app_dir: &Path, home_dir: &Path, channel: Option<Channel>) -> Result<()> {\n    let app_basename = app_dir\n        .file_name()\n        .ok_or_else(|| anyhow!(\"Failed to get app bundle name\"))?;\n\n    let install_app = home_dir.join(\"Applications\").join(app_basename);\n    let install_app_backup = home_dir\n        .join(\"Applications\")\n        .join(format!(\"{}.backup\", app_basename.to_string_lossy()));\n    let install_app_new = home_dir\n        .join(\"Applications\")\n        .join(format!(\"{}.new\", app_basename.to_string_lossy()));\n\n    info(&format!(\n        \"Installing{} to {}...\",\n        channel\n            .map(|c| format!(\" channel {}\", c.display_name()))\n            .unwrap_or_default(),\n        install_app.display()\n    ));\n\n    // Clean up any leftover temp files from previous failed installations","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/install_macos.rs#L55-L91","documentation":"Thrown in install_app in install_macos.rs when app_dir.file_name() returns None, i.e. the extracted .app bundle path terminates in '..' or is a root path. extract_tarball returns a directory entry found via read_dir, which always has a normal file name, so this is a defensive guard against impossible paths rather than a realistic runtime failure.","triggerScenarios":"app_dir being \"/\" or ending in \"..\" when install_app computes the destination bundle name under ~/Applications; only possible if a caller hand-constructs app_dir instead of using extract_tarball's output.","commonSituations":"Not observed in normal installs. Appears only in tests or custom code that calls install_app directly with a synthesized path; treat occurrences as a caller bug.","solutions":["Call install_app with the directory returned by extract_tarball, not a hand-built path.","If invoking directly, pass a concrete .app directory path (e.g. .../GitButler.app), never a root or '..'-terminated path."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before install_app(app_dir, ...)\nfn is_valid_app_dir(p: &std::path::Path) -> bool {\n    p.file_name().map(|n| n.to_string_lossy().ends_with(\".app\")).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call install_app with directories produced by extract_tarball.","In tests/direct calls, pass a concrete '<Name>.app' path, never root or '..'."],"tags":["installer","macos","app-bundle","filesystem-path","defensive-code"],"backgroundTag":"invalid-file-path","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}