jlcodes99/cockpit-tools · warning · std::io::Error

TimedOut

TimedOut

Error message

PowerShell 进程探测超时({}ms)

What it means

`powershell_output_with_timeout` spawns a PowerShell child process to enumerate application processes; if the child does not finish within the configured timeout, it is killed and an `std::io::Error` with `ErrorKind::TimedOut` and message "PowerShell 进程探测超时({N}ms)" is returned. Callers (`collect_*_process_entries_from_powershell` for Codex, Antigravity, CodeBuddy, WorkBuddy) then fail their process discovery step.

Source

Thrown at crates/cockpit-core/src/modules/process_core_discovery.rs:460

            if let Some(mut out) = child.stdout.take() {
                let _ = out.read_to_end(&mut stdout);
            }
            if let Some(mut err) = child.stderr.take() {
                let _ = err.read_to_end(&mut stderr);
            }
            let result = Ok(std::process::Output {
                status,
                stdout,
                stderr,
            });
            log_command_trace_result(&preview, &result, start.elapsed());
            return result;
        }

        if start.elapsed() >= timeout {
            let _ = child.kill();
            let _ = child.wait();
            let result = Err(Error::new(
                ErrorKind::TimedOut,
                format!("PowerShell 进程探测超时({}ms)", timeout.as_millis()),
            ));
            log_command_trace_result(&preview, &result, start.elapsed());
            return result;
        }

        thread::sleep(Duration::from_millis(100));
    }
}

#[cfg(target_os = "windows")]
fn cmd_output(args: &[&str]) -> std::io::Result<std::process::Output> {
    use std::os::windows::process::CommandExt;

    let mut command = Command::new("cmd");
    command.creation_flags(CREATE_NO_WINDOW).args(args);
    let preview = format_command_preview(&command);

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Retry the discovery call — a warm PowerShell usually completes well within the timeout on the second run.
  2. Increase the timeout constant passed to `powershell_output_with_timeout` (e.g. 3s → 10s).
  3. Launch PowerShell with `-NoProfile` to skip slow profile scripts.
  4. Reduce the query cost (narrow the WMI/CIM filter) so enumeration finishes faster.

Example fix

// before
let entries = collect_codex_process_entries_from_powershell()?;
// after
let entries = match collect_codex_process_entries_from_powershell() {
    Ok(e) => e,
    Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
        log::warn!("process discovery timed out, retrying once");
        collect_codex_process_entries_from_powershell().unwrap_or_default()
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: retry

Validate before calling

// best-effort pre-check (Windows)
// ensure powershell.exe resolves before the timed call
which::which("powershell").map_err(|_| std::io::Error::new(std::io::ErrorKind::NotFound, "powershell not on PATH"))?

Type guard

fn is_probe_timeout(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::TimedOut && e.to_string().contains("PowerShell 进程探测超时")
}

Try / catch

match powershell_output_with_timeout(&mut child, timeout) {
    Ok(out) => out,
    Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
        log::warn!("probe timed out; retrying with warm powershell");
        retry_once_or_default()
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: PowerShell startup or the process query takes longer than the timeout budget — cold PowerShell first-run (profile loading, .NET JIT), heavily loaded CPU, or a very large number of running processes making the WMI/CIM query slow.

Common situations: First invocation after boot on Windows when PowerShell is not warm; antivirus scanning powershell.exe on launch; slow machines with hundreds of processes; overly tight timeout constants.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/1939df0a792183dc. Report an issue: GitHub.