BigPizzaV3/CodexPlusPlus · error · anyhow::Error
macOS open command is empty
Error message
macOS open command is empty
What it means
On macOS, when the resolved app_dir ends in .app the launcher builds an `open`-style argv via build_macos_open_command (or its native-menu-inspector variant) and guards that the vector is non-empty before Command::new (crates/codex-plus-core/src/launcher.rs:784-786). The builders always seed the vector with the open executable path, so an empty command indicates a broken builder invocation (custom build_macos_open_command_* override, bad refactor, or empty app_dir producing degenerate output) rather than a normal runtime condition.
Source
Thrown at crates/codex-plus-core/src/launcher.rs:786
if app_dir.extension().and_then(|value| value.to_str()) == Some("app") {
let cleanup_policy = if is_macos_app_running(app_dir).await {
MacosCleanupPolicy::SkipQuitBecauseAlreadyRunning
} else {
MacosCleanupPolicy::QuitIfNotPreviouslyRunning
};
let command = if let Some(inspector_port) = native_menu_inspector_port {
build_macos_open_command_with_native_menu_inspector(
app_dir,
debug_port,
inspector_port,
&launch_extra_args,
)
} else {
build_macos_open_command(app_dir, debug_port, &launch_extra_args)
};
let executable = command
.first()
.ok_or_else(|| anyhow::anyhow!("macOS open command is empty"))?;
let child = Command::new(executable)
.args(&command[1..])
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.context("failed to launch macOS Codex app")?;
*self.child.lock().await = Some(child);
if let Some(inspector_port) = native_menu_inspector_port {
start_native_menu_localizer(inspector_port);
}
return Ok(CodexLaunch::Process {
command,
wait_strategy: ProcessWaitStrategy::ExternalWaitCommand,
macos_cleanup_policy: Some(cleanup_policy),
});
}
let command = if let Some(inspector_port) = native_menu_inspector_port {View on GitHub (pinned to 1f431ae49b)
Solutions
- If you forked or wrapped build_macos_open_command*, restore the unconditional first element (the `open` executable) so the vec is never empty
- Check the resolved app_dir is non-empty and has extension .app before launch; a malformed dir points at an upstream app-path resolution problem
- If unreachable in your build, treat as an assertion failure: report the full settings/app_dir used and file it upstream rather than catching it
Example fix
// before
fn build_macos_open_command(app_dir: &Path, debug_port: u16, extra: &[String]) -> Vec<String> {
let mut command = Vec::new(); // may stay empty
...
}
// after
fn build_macos_open_command(app_dir: &Path, debug_port: u16, extra: &[String]) -> Vec<String> {
let mut command = vec!["/usr/bin/open".to_string()]; // never empty
...
} Defensive patterns
Strategy: validation
Validate before calling
// Before launch, sanity-check the macOS branch inputs
#[cfg(target_os = "macos")]
fn macos_launch_ready(app_dir: &Path) -> bool {
app_dir.extension().and_then(|e| e.to_str()) == Some("app")
&& app_dir.join("Contents/MacOS").is_dir()
} Type guard
fn non_empty_command(cmd: &[String]) -> bool {
cmd.first().is_some_and(|exe| !exe.trim().is_empty())
} Try / catch
// Guard is an invariant; if it ever fires, capture diagnostics rather than retry:
Err(e) if e.to_string() == "macOS open command is empty" => {
anyhow::bail!("internal invariant broken: builder returned empty argv for {}", app_dir.display())
} Prevention
- Never modify build_macos_open_command* to conditionally omit the executable element
- Unit-test builders: assert !build_macos_open_command(app_dir, port, &[]).is_empty()
- Validate app_dir resolves to a real .app bundle before invoking launch
When it happens
Trigger: app_dir has extension "app", is_macos launch branch is taken, and build_macos_open_command / build_macos_open_command_with_native_menu_inspector returns a Vec with zero elements — e.g. after a refactor that conditionally skips pushing the executable, or a copied/modified builder in a fork.
Common situations: Fork modifications to the macOS command builders; passing an empty Path as app_dir so path formatting yields nothing; regression after changing build_macos_open_command's return construction; this is effectively an unreachable defensive invariant in stock builds.
Related errors
- Codex command is empty
- provider sync requires launcher hooks with codex-plus-data i
- Remote Control session recovery requires launcher hooks with
- downloaded openai/plugins marketplace root mismatch
- 解压后的请求体超过大小限制
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/a5fa90b78c509b43.
Report an issue: GitHub.