{"record":{"id":"f4f31e7c50ee7fab","repo":"jdx/mise","slug":"another-process-is-installing-the-mise-notificatio","errorCode":null,"errorMessage":"another process is installing the mise notification helper","messagePattern":"another process is installing the mise notification helper","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/system/history/notify/macos.rs","lineNumber":71,"sourceCode":"    let app = ensure_app(&crate::dirs::DATA.join(\"notifications\"))?;\n    Ok(notification_command(&app, title, body))\n}\n\nfn notification_command(app: &Path, title: &str, body: &str) -> Command {\n    let mut command = Command::new(executable(app));\n    command.args([title, body]);\n    command\n}\n\nfn ensure_app(root: &Path) -> Result<PathBuf> {\n    let app = app_path(root);\n    if complete(&app) {\n        return Ok(app);\n    }\n    crate::file::create_dir_all(root)?;\n    let mut lock = fslock::LockFile::open(&root.join(\"install.lock\"))?;\n    if !lock.try_lock()? {\n        bail!(\"another process is installing the mise notification helper\");\n    }\n    if complete(&app) {\n        return Ok(app);\n    }\n    let staging = tempfile::tempdir_in(root)?;\n    let staged = staging.path().join(\"mise.app\");\n    let contents = staged.join(\"Contents\");\n    std::fs::create_dir_all(contents.join(\"MacOS\"))?;\n    std::fs::create_dir_all(contents.join(\"Resources\"))?;\n    std::fs::create_dir_all(contents.join(\"_CodeSignature\"))?;\n    std::fs::write(executable(&staged), HELPER)?;\n    std::fs::set_permissions(executable(&staged), std::fs::Permissions::from_mode(0o755))?;\n    std::fs::write(contents.join(\"Info.plist\"), INFO)?;\n    std::fs::write(contents.join(\"Resources/mise.icns\"), ICON)?;\n    std::fs::write(\n        contents.join(\"_CodeSignature/CodeResources\"),\n        CODE_RESOURCES,\n    )?;","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/notify/macos.rs#L53-L89","documentation":"ensure_app stages and installs the notification helper app into the data directory under an install.lock fslock. When a complete app is not already present and another process holds the lock, it bails out so only one installer runs at a time, preventing two processes from corrupting the staged bundle.","triggerScenarios":"Concurrent calls to notification()/ensure_app (e.g. two mise processes emitting notifications) where the app is absent or incomplete and both race to acquire root/install.lock; a stale/crashed process briefly holding the lock.","commonSituations":"Multiple shells or scripts firing notifications simultaneously on first run; CI or parallel test runs sharing the same data directory; an interrupted first installation leaving an incomplete app so every process takes the lock path.","solutions":["Retry after a short delay — once the other process finishes installing, complete() succeeds and the lock path is skipped.","Check for a hung process holding install.lock (lsof on the data dir) and wait or kill it.","If a crashed installer left a partial bundle, remove the incomplete app in the data dir and let the next call repair it.","Serialize notification setup in your scripts (only one mise process should install the helper first)."],"exampleFix":"// before: parallel notification calls racing\nmise notify & mise notify &\n// after: serialize first-time install\nmise notify && mise notify  # or wait for the first install to complete","handlingStrategy":"retry","validationCode":"let lock_free = !std::path::Path::new(&data_dir).join(\"notifications/install.lock\")\n    .metadata().map(|m| m.len() > 0).unwrap_or(false); // advisory only; rely on retry","typeGuard":null,"tryCatchPattern":"for attempt in 0..5 {\n    match ensure_app(root) {\n        Err(e) if e.to_string().contains(\"another process is installing\") => {\n            std::thread::sleep(Duration::from_millis(500 * (attempt + 1)));\n        }\n        other => { other?; break; }\n    }\n}","preventionTips":["Let the first mise invocation install the helper before firing parallel notifications.","Avoid sharing one data directory across concurrent CI jobs.","Clean up partial installs after a crashed first run."],"tags":["concurrency","file-lock","macos","notifications"],"backgroundTag":"file-lock-contention","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}