BigPizzaV3/CodexPlusPlus · error · anyhow::Error
Codex command is empty
Error message
Codex command is empty
What it means
In the non-.app launch branch (Windows/Linux or direct executable), the launcher builds the Codex argv via build_codex_command / build_codex_command_with_native_menu_inspector and requires a first element (the executable path from app_paths::build_codex_executable) before spawning (crates/codex-plus-core/src/launcher.rs:814-816). Both builders unconditionally start with the executable string, so this error is a defensive invariant against a modified/empty builder, not an expected runtime outcome.
Source
Thrown at crates/codex-plus-core/src/launcher.rs:816
command,
wait_strategy: ProcessWaitStrategy::ExternalWaitCommand,
macos_cleanup_policy: Some(cleanup_policy),
});
}
let command = if let Some(inspector_port) = native_menu_inspector_port {
build_codex_command_with_native_menu_inspector(
app_dir,
debug_port,
inspector_port,
&launch_extra_args,
)
} else {
build_codex_command(app_dir, debug_port, &launch_extra_args)
};
let executable = command
.first()
.ok_or_else(|| anyhow::anyhow!("Codex command is empty"))?;
let mut child_command = Command::new(executable);
child_command
.args(&command[1..])
.stdout(Stdio::null())
.stderr(Stdio::null());
#[cfg(windows)]
child_command.creation_flags(crate::windows_integration::CREATE_NO_WINDOW);
let child = child_command
.spawn()
.with_context(|| format!("failed to launch Codex executable {executable}"))?;
*self.child.lock().await = Some(child);
if let Some(inspector_port) = native_menu_inspector_port {
start_native_menu_localizer(inspector_port);
}
Ok(CodexLaunch::Process {
command,
wait_strategy: ProcessWaitStrategy::TrackedChild,
macos_cleanup_policy: None,View on GitHub (pinned to 1f431ae49b)
Solutions
- Restore the unconditional executable first element in any forked build_codex_command* so the vec is never empty
- Validate app_dir resolution before launching: ensure resolve_app_dir returned a real directory containing the platform binary
- Treat as an assertion: log the full launch inputs and report upstream if it fires in an unmodified build
Example fix
// before (test stub that trips the guard)
let command: Vec<String> = Vec::new();
let executable = command.first().ok_or_else(|| anyhow!("Codex command is empty"))?;
// after
let mut command = vec![crate::app_paths::build_codex_executable(app_dir).to_string_lossy().to_string()];
command.extend(build_codex_arguments(debug_port, extra_args));
let executable = &command[0]; Defensive patterns
Strategy: validation
Validate before calling
let command = build_codex_command(app_dir, debug_port, &launch_extra_args);
if command.first().map(String::is_empty).unwrap_or(true) {
anyhow::bail!("refusing to spawn: codex command empty for {}", app_dir.display());
} Type guard
fn spawnable_command(cmd: &[String]) -> Option<&str> {
cmd.first().map(|s| s.as_str()).filter(|s| !s.trim().is_empty())
} Try / catch
// Invariant failure: report inputs, do not retry
match launcher.launch().await {
Err(e) if e.to_string() == "Codex command is empty" => {
tracing::error!(?app_dir, %debug_port, "command builder regression");
return Err(e.context("command builder returned empty argv"));
}
rest => rest,
} Prevention
- Keep the executable as the unconditional first vec element in builder forks
- Assert builder invariants in unit tests: first element equals build_codex_executable(app_dir)
- Resolve and validate app_dir (directory containing the platform binary) before launching
When it happens
Trigger: Launching with an app_dir that is not a .app bundle while a customized build_codex_command* variant returns an empty Vec — e.g. fork code that builds args conditionally, or a stubbed builder in tests that returns Vec::new().
Common situations: Forks that rewrite command assembly; unit tests mocking command builders with empty returns; regressions after changing build_codex_executable to return an empty PathBuf that then formats to an empty-but-present string (note: that yields an empty executable string, not this error — this error needs a literally empty Vec).
Related errors
- macOS open 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/c02f63b065e5e91a.
Report an issue: GitHub.