BigPizzaV3/CodexPlusPlus · error
启动安装包失败:
Error message
启动安装包失败:{error} What it means
On Windows, launch_installer spawns the downloaded installer with std::process::Command::new(path) plus CREATE_NO_WINDOW. If the OS fails to spawn the process, the error is mapped to 启动安装包失败:{error} with the raw io::Error text embedded. Common io errors: file not found, access denied, or the file is not a valid executable.
Solutions
- Read the embedded io error: NotFound → file missing; AccessDenied → AV/permissions; invalid exe → corrupt download.
- Verify the installer file exists at the UpdateInstall/installer_path and re-download if missing.
- Add the installer/URL to antivirus exclusions or whitelist the app if AV is blocking spawn.
- Re-run perform_update to get a fresh, complete download (a corrupt/truncated file will also fail to spawn).
- Launch the installer manually by double-clicking the downloaded file to isolate launcher vs installer problems.
Example fix
// before
let install = perform_update(&release, &dir).await?;
// after
match perform_update(&release, &dir).await {
Ok(i) if i.launched => println!("installer started: {}", i.installer_path.display()),
Ok(i) => println!("downloaded, run manually: {}", i.installer_path.display()),
Err(e) if e.to_string().contains("启动安装包失败") => {
eprintln!("spawn failed: {e}; run {} manually", expected_path.display());
}
Err(e) => return Err(e),
} Defensive patterns
Strategy: try-catch
Validate before calling
fn installer_launchable(path: &std::path::Path) -> bool {
path.is_file() && std::fs::metadata(path).map_or(false, |m| m.len() > 0)
} Try / catch
match perform_update(&release, &dir).await {
Ok(install) if install.launched => Ok(install),
Ok(install) => {
// launched == false on unsupported platforms; on Windows treat as manual install
open_in_explorer(&install.installer_path); Ok(install)
}
Err(e) if e.to_string().contains("启动安装包失败") => {
eprintln!("spawn failed: {e}; instruct user to run the installer manually");
Err(e)
}
Err(e) => Err(e),
} Prevention
- Always surface installer_path to the user so a failed spawn can be completed manually.
- Whitelist the app/installer in AV/SmartScreen policies on managed Windows machines.
- Verify the downloaded file size before launch to avoid spawning truncated/corrupt exes.
- Don't delete the temp download dir while the update flow is running.
When it happens
Trigger: Calling perform_update on Windows when: the installer file was deleted/moved between download and launch; antivirus quarantined or blocked execution of the freshly downloaded .exe; the path contains characters the launcher mishandles; the downloaded file is corrupt or not a PE executable; insufficient permissions in the target directory.
Common situations: Windows Defender / SmartScreen marking the unsigned installer and blocking spawn; MSI vs NSIS mismatch causing 'not a valid Win32 application'; download truncated so the exe is corrupt; running from a temp dir cleaned concurrently.
Related errors
- 打开 DMG 失败:
- 当前平台不支持启动安装包
- Cannot run remote git over SSH
- cannot terminate Windows process id
- Cannot verify launcher process identity
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/bfd51d570a2c23a3.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/update.rs:418
|| name.ends_with("setup.exe")
|| name.ends_with("installer.exe"))
}
fn is_macos_installer_asset(name: &str) -> bool {
// Loose shape check; arch preference is handled by platform_asset_rank
// via is_macos_native_arch_asset.
name.contains("codex") && name.contains("plus") && name.ends_with(".dmg")
}
pub fn launch_installer(path: &Path) -> anyhow::Result<()> {
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
std::process::Command::new(path)
.creation_flags(crate::windows_integration::CREATE_NO_WINDOW)
.spawn()
.map(|_| ())
.map_err(|error| anyhow::anyhow!("启动安装包失败:{error}"))
}
#[cfg(target_os = "macos")]
{
std::process::Command::new("open")
.arg(path)
.spawn()
.map(|_| ())
.map_err(|error| anyhow::anyhow!("打开 DMG 失败:{error}"))
}
#[cfg(all(not(windows), not(target_os = "macos")))]
{
let _ = path;
anyhow::bail!("当前平台不支持启动安装包")
}
}
View on GitHub (pinned to b1ed92e5e4)