uutils/coreutils · error · io::Error

kill-error-unsupported-signal

Error message

kill-error-unsupported-signal

What it means

On Windows, kill can only deliver a limited set of signals via native APIs. Requesting a signal the platform cannot send — notably SIGNAL_STOP (suspend), or any unimplemented signal number — returns io::ErrorKind::Unsupported with this translated message. It is a platform-capability limitation, not a bad PID or permission issue.

Source

Thrown at src/uu/kill/src/platform/windows.rs:22

// file that was distributed with this source code.

// spell-checker:ignore pids

//! Windows implementation of `kill`'s platform facade, built on the signal
//! emulation in [`uucore::process`]. PID 0 targets the Job object `kill` runs
//! in, the closest Windows analog of a process group. STOP (no process-suspend
//! API) and negative pids (no way to name another process's group) are
//! rejected.

use std::io;

use uucore::process::{enable_debug_privilege, send_signal_to_own_group, send_signal_to_pid};
use uucore::translate;

const SIGNAL_STOP: usize = 19;

fn unsupported(message: String) -> io::Error {
    io::Error::new(io::ErrorKind::Unsupported, message)
}

pub(crate) fn send_signal(pid: i32, sig: usize) -> io::Result<()> {
    if sig == SIGNAL_STOP {
        return Err(unsupported(translate!("kill-error-unsupported-signal")));
    }
    match u32::try_from(pid) {
        // Fails exactly for pid < 0.
        Err(_) => Err(unsupported(translate!(
            "kill-error-negative-pid-unsupported"
        ))),
        Ok(pid) => {
            // Group members need the same rights as a single target.
            enable_debug_privilege();
            if pid == 0 {
                send_signal_to_own_group(sig)
            } else {
                send_signal_to_pid(pid, sig)

View on GitHub (pinned to 325183372a)

Solutions

  1. Avoid STOP-type signals on Windows; terminate with a supported signal or use process suspension APIs explicitly
  2. Guard the call at runtime: check target OS (cfg!(windows)) and skip/replace suspend logic there
  3. On Windows use taskkill /PID <pid> for termination or a Windows-specific suspend mechanism (NtSuspendProcess) via a crate
  4. Refactor job control to be POSIX-only, gating it behind a unix-only code path

Example fix

// before
kill::send_signal(pid, 19)?; // SIGNAL_STOP
// after
if cfg!(windows) {
    eprintln!("suspend not supported on windows");
} else {
    kill::send_signal(pid, 19)?;
}
Defensive patterns

Strategy: fallback

Validate before calling

// check signal support on the current platform before sending
const SIGNAL_STOP: usize = 19;
if cfg!(windows) && (sig == SIGNAL_STOP) {
    eprintln!("{sig} unsupported on windows");
    return;
}

Type guard

fn signal_supported(sig: usize) -> bool {
    !(cfg!(windows) && sig == 19) // SIGNAL_STOP
}

Try / catch

match kill::send_signal(pid, sig) {
    Err(e) if e.kind() == std::io::ErrorKind::Unsupported => {
        eprintln!("signal {sig} unsupported here; using termination instead");
        kill::send_signal(pid, default_terminate_signal)?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling kill's send_signal(pid, sig) on Windows with sig == 19 (SIGNAL_STOP) or another signal Windows does not support (e.g., simulating SIGTSTP/SIGSTOP semantics).

Common situations: Scripts written for Unix that `kill -STOP`/`kill -TSTP` a process, job-control emulation in shells on Windows, cross-platform tooling that suspends/resumes worker processes.

Related errors


AI-assisted analysis of uutils/coreutils@325183372a (2026-08-31). Data as JSON: /api/errors/7724ac181ffbc786. Report an issue: GitHub.