{"record":{"id":"5603e8e0eb0abdd5","repo":"BigPizzaV3/CodexPlusPlus","slug":"dmg-error","errorCode":null,"errorMessage":"打开 DMG 失败：{error}","messagePattern":"打开 DMG 失败：(.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/update.rs","lineNumber":427,"sourceCode":"\npub fn launch_installer(path: &Path) -> anyhow::Result<()> {\n    #[cfg(windows)]\n    {\n        use std::os::windows::process::CommandExt;\n        std::process::Command::new(path)\n            .creation_flags(crate::windows_integration::CREATE_NO_WINDOW)\n            .spawn()\n            .map(|_| ())\n            .map_err(|error| anyhow::anyhow!(\"启动安装包失败：{error}\"))\n    }\n\n    #[cfg(target_os = \"macos\")]\n    {\n        std::process::Command::new(\"open\")\n            .arg(path)\n            .spawn()\n            .map(|_| ())\n            .map_err(|error| anyhow::anyhow!(\"打开 DMG 失败：{error}\"))\n    }\n\n    #[cfg(all(not(windows), not(target_os = \"macos\")))]\n    {\n        let _ = path;\n        anyhow::bail!(\"当前平台不支持启动安装包\")\n    }\n}\n","sourceCodeStart":409,"sourceCodeEnd":436,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/update.rs#L409-L436","documentation":"On macOS, launch_installer runs Command::new(\"open\").arg(path) to mount the DMG; \"打开 DMG 失败：{error}\" wraps a failure to spawn the open command itself. Because the binary is resolved via PATH, the realistic trigger is a sanitized environment (the app launched without a standard PATH that includes /usr/bin) or a system policy blocking process spawning. Only spawn failure is reported — whether the DMG actually mounted is not awaited.","triggerScenarios":"The manager app is started by a launcher/daemon with a scrubbed environment so PATH does not include /usr/bin; the open binary is missing; hardened-runtime/sandbox policy denies spawning.","commonSituations":"Apps started by launchd/supervisord-style wrappers with minimal environments; sandboxed or policy-restricted macOS setups; CI contexts calling launch_installer without a normal user session.","solutions":["Ensure the process environment has a sane PATH (at minimum /usr/bin) before launching","If you maintain the crate, resolve open by absolute path (/usr/bin/open) instead of PATH lookup","Verify the DMG path exists before launching","If policy restricts spawning, mount the DMG from a helper that is allowed to spawn processes"],"exampleFix":"// before (library-internal)\nstd::process::Command::new(\"open\").arg(path).spawn()\n\n// after\nstd::process::Command::new(\"/usr/bin/open\").arg(path).spawn()","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match launch_installer(&install.installer_path) {\n    Ok(()) => { /* spawned */ }\n    Err(err) if err.to_string().contains(\"打开 DMG 失败\") => {\n        // inspect PATH in this process; if /usr/bin is missing, re-spawn with a fixed PATH env\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Launch the app with a standard environment (PATH including /usr/bin)","If maintaining the crate, resolve open by absolute path /usr/bin/open","Verify the DMG path exists before invoking launch_installer"],"tags":["macos","dmg","installer","process-spawn","update"],"backgroundTag":"installer-launch-failed","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}