jlcodes99/cockpit-tools · error

{} ({})

Error message

{} ({})

What it means

Generic process-teardown failure formatted as "{failure_message} ({pid_list})" in the shared close-and-verify routine of process_core_matching: after graceful close, close_pids, and a forced retry, collect_remaining_entries still finds processes matching the target dirs. The message names the failing operation and lists the PIDs that remain alive.

Source

Thrown at crates/cockpit-core/src/modules/process_core_matching.rs:3306

            if let Err(err) = close_pids(&remaining_pids, 6) {
                crate::modules::logger::log_warn(&format!(
                    "[{}] retry close_pids returned error: {}",
                    log_prefix, err
                ));
            }
            remaining_entries = collect_remaining_entries(&target_dirs);
        }
    }

    if !remaining_entries.is_empty() {
        let remaining_pids = collect_remaining_pids(&remaining_entries);
        if let Some(detail_logger_fn) = detail_logger {
            detail_logger_fn(&remaining_pids);
        }
        crate::modules::logger::log_error(&format!(
            "[{}] still_running_entries={}",
            log_prefix,
            summarize_process_entries_for_log(&remaining_entries)
        ));
        return Err(format!(
            "{} ({})",
            failure_message,
            summarize_pid_list_for_log(&remaining_pids)
        ));
    }

    Ok(())
}

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Manually terminate the PIDs listed in parentheses in the message (kill -9 / Task Manager), then retry.
  2. Check whether a supervisor or auto-restart mechanism relaunches the processes; disable it before closing.
  3. Run with sufficient privileges (elevate) so signals can reach processes owned by other accounts.
  4. Increase the timeout or repeat the close once — the routine already retries force-kill with a 6s window.
  5. Inspect the '[<prefix>] still_running_entries=' log line to see which processes/dirs remained and why.

Example fix

// before: assuming close success
assert!(close_managed_instances_common().is_ok());
// after: parse remaining PIDs from the failure and escalate
match close_managed_instances_common() {
    Err(msg) => {
        let pids = extract_parenthesized_pids(&msg);
        force_kill_elevated(&pids); // taskkill /F /PID ... or kill -9
    }
    Ok(_) => {}
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before closing, verify no supervisor will respawn the targets
fn no_respawn_expected(match_cmdline: &str) -> bool {
    !list_running_processes().iter().any(|p| {
        p.cmdline.contains("supervisor") && p.cmdline.contains(match_cmdline)
    })
}

Type guard

fn parse_remaining_pids(err_msg: &str) -> Vec<u32> {
    err_msg.rsplit_once('(').and_then(|(_, tail)| tail.trim_end_matches(')').split_whitespace().next())
        .map(|s| s.split(',').filter_map(|p| p.trim().parse().ok()).collect())
        .unwrap_or_default()
}

Try / catch

match close_managed_instances() {
    Err(msg) => {
        let pids = parse_remaining_pids(&msg);
        eprintln!("teardown failed, force-killing {:?}", pids);
        force_kill_elevated(&pids); // taskkill /F or kill -9
    }
    Ok(_) => {}
}

Prevention

When it happens

Trigger: Calling any managed-instance close flow (Codex/Trae/opencode instances) when, even after two close_pids passes (graceful wait + 6s force retry), processes identified via target_dirs are still running — blocked signals, elevation mismatch, or respawned child processes.

Common situations: Supervisor/parent process respawning killed children; processes running under a different user; hung processes in uninterruptible wait; file locks held in the target dirs keeping processes alive; insufficient permissions without elevation.

Related errors


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