{"record":{"id":"1674c090d8807a60","repo":"gitbutlerapp/gitbutler","slug":"no-cli-wrapper-configured-for","errorCode":null,"errorMessage":"No CLI wrapper configured for {}","messagePattern":"No CLI wrapper configured for (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/open/program.rs","lineNumber":593,"sourceCode":"}\n\n/// A canonically installed macOS application with a bundle ID and an optional CLI wrapper.\n#[cfg(target_os = \"macos\")]\n#[derive(Clone, Debug, PartialEq)]\npub struct MacosApplication {\n    /// macOS bundle identifier for the application.\n    pub bundle_identifier: String,\n    /// Location of the CLI wrapper inside the application bundle, if it exists.\n    pub cli_wrapper_path: Option<String>,\n}\n\n#[cfg(target_os = \"macos\")]\nimpl MacosApplication {\n    #[cfg(target_os = \"macos\")]\n    fn resolve_cli_wrapper_abspath(&self) -> anyhow::Result<PathBuf> {\n        let app_dir_path = self.find_app_directory()?;\n        let cli_wrapper_path = self.cli_wrapper_path.as_deref().ok_or_else(|| {\n            anyhow::anyhow!(\"No CLI wrapper configured for {}\", self.bundle_identifier)\n        })?;\n        Ok(app_dir_path.join(cli_wrapper_path))\n    }\n\n    #[cfg(target_os = \"macos\")]\n    fn find_app_directory(&self) -> anyhow::Result<PathBuf> {\n        use objc2_app_kit::NSWorkspace;\n        use objc2_foundation::NSString;\n\n        let workspace = NSWorkspace::sharedWorkspace();\n        let bundle_identifier = NSString::from_str(&self.bundle_identifier);\n        let app_url = workspace\n            .URLForApplicationWithBundleIdentifier(&bundle_identifier)\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"Could not find application for '{}'\",\n                    self.bundle_identifier\n                )","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/open/program.rs#L575-L611","documentation":"Thrown by MacosApplication::resolve_cli_wrapper_abspath in but-api's program-open flow when a configured macOS application declares no cli_wrapper_path. The routine needs the wrapper's location inside the .app bundle to build an absolute path next to the bundle directory; with the field None there is nothing to join, so it bails immediately. The application itself is located afterwards via Launch Services, so this error is purely about incomplete app registration data, not about the app being missing.","triggerScenarios":"Calling the open-in-application flow (open_in_macos_application, which calls resolve_cli_wrapper_abspath) with a MacosApplication entry whose cli_wrapper_path is None - for example a newly registered app in the program table that never declared its wrapper, or a config/schema change that made the field optional and silently dropped old values.","commonSituations":"Adding a new macOS target app to the launcher configuration and forgetting cli_wrapper_path; a serialization change that loses the field for existing entries; a bundling change where the CLI wrapper was removed from the app bundle entirely.","solutions":["Set cli_wrapper_path on the MacosApplication entry to the wrapper's path inside the .app bundle (e.g. \"Contents/MacOS/myapp-cli\")","Verify the wrapper actually ships in the installed bundle: ls /Applications/MyApp.app/Contents/MacOS/","If the target app has no CLI, route the request away from resolve_cli_wrapper_abspath instead of leaving the field empty"],"exampleFix":"// before\nMacosApplication {\n    bundle_identifier: \"com.example.MyApp\".into(),\n    cli_wrapper_path: None,\n}\n\n// after\nMacosApplication {\n    bundle_identifier: \"com.example.MyApp\".into(),\n    cli_wrapper_path: Some(\"Contents/MacOS/myapp-cli\".into()),\n}","handlingStrategy":"validation","validationCode":"// Rust: check before resolving the CLI wrapper path\nmatch app.cli_wrapper_path.as_deref() {\n    Some(p) if !p.is_empty() => {\n        // safe to call resolve_cli_wrapper_abspath / the CLI-open flow\n    }\n    _ => {\n        // pick another open strategy; do not enter the wrapper flow\n    }\n}","typeGuard":"fn has_cli_wrapper(app: &MacosApplication) -> bool {\n    app.cli_wrapper_path.as_deref().is_some_and(|p| !p.is_empty())\n}","tryCatchPattern":"match resolve(&app) {\n    Err(err) if err.to_string().starts_with(\"No CLI wrapper configured\") => {\n        // fall back to a non-CLI open strategy\n    }\n    result => result,\n}","preventionTips":["Treat cli_wrapper_path as required when registering apps that support CLI open","Add a startup validation pass that rejects MacosApplication entries with a None wrapper","Cover the open configuration with a test asserting every macOS entry has cli_wrapper_path set"],"tags":["macos","cli-wrapper","configuration","application-bundle"],"backgroundTag":"missing-config-value","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}