BigPizzaV3/CodexPlusPlus · error
Cannot verify launcher process identity
Error message
Cannot verify launcher process identity: {pid} What it means
capture() snapshots launcher process identity by reading each PID's birth id via the Windows integration layer. If process_birth_id returns None for any PID, the process identity cannot be verified and capture aborts with this error so the watcher never waits on the wrong process.
Solutions
- Verify the launcher is still running right before calling capture and pass the pid of a live process
- Re-scan the process list to obtain a fresh pid and retry capture
- Treat the error as transient: retry capture shortly after spawn, or skip waiting for the dead launcher and report it as exited
Example fix
// before
let snapshot = LauncherSnapshot::capture(&[stale_pid], ...)?;
// after
if crate::windows_integration::process_birth_id(pid).is_some() {
let snapshot = LauncherSnapshot::capture(&[pid], ...)?;
} else {
// respawn launcher and recapture with fresh pid
} Defensive patterns
Strategy: retry
Validate before calling
fn pid_alive(pid: u32) -> bool {
crate::windows_integration::process_birth_id(pid).is_some()
} Type guard
fn verified_pid(pid: u32) -> Option<u32> {
crate::windows_integration::process_birth_id(pid).map(|_| pid)
} Try / catch
match LauncherSnapshot::capture(&[pid], ...) {
Err(e) if e.to_string().contains("Cannot verify launcher process identity") => {
// process exited before snapshot; rescan and retry once
}
other => other?,
} Prevention
- Capture immediately after spawning the launcher to minimize the race window
- Never cache pids across sessions; re-derive them from the process list
- Treat capture failure as 'launcher died early' and surface that to the user
When it happens
Trigger: Calling capture with a PID that has already exited, or a PID for which the OS denies/omits creation-time info (recycled PID, protected process, invalid pid).
Common situations: Launcher crashed before the watcher could snapshot it; PID reuse gave a stale id; spawning raced with process exit; passing an incorrect pid parsed from stale state.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- bridge context is not initialized
- cannot terminate Windows process id
- cannot wait for Windows process id
- 当前对话尚未读取完成,请稍后重试
- 当前对话尚未读取完成,请稍后重试
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/64f75ed90d3757f4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/watcher.rs:568
#[cfg(windows)]
pub struct LauncherExitSnapshot {
processes: Vec<(u32, u64)>,
}
#[cfg(windows)]
impl LauncherExitSnapshot {
pub fn capture() -> anyhow::Result<Self> {
let processes = crate::windows_integration::enumerate_processes();
let ids = filter_killable_launcher_processes(
processes.iter().map(|p| (p.process_id, p.parent_process_id, p.exe_file.as_str())),
std::process::id(),
);
let mut captured = Vec::new();
for pid in ids {
if let Some(birth) = crate::windows_integration::process_birth_id(pid) {
captured.push((pid, birth));
} else {
anyhow::bail!("Cannot verify launcher process identity: {pid}");
}
}
Ok(Self { processes: captured })
}
pub fn wait_for_exit(self, timeout: Duration) -> anyhow::Result<()> {
let deadline = std::time::Instant::now() + timeout;
loop {
let remaining = launcher_incarnations_still_running(
&self.processes,
|pid| crate::windows_integration::process_birth_id(pid),
);
if remaining.is_empty() {
return Ok(());
}
anyhow::ensure!(
std::time::Instant::now() < deadline,
"Previous launcher has not exited; no process was forcibly terminated"View on GitHub (pinned to b1ed92e5e4)