orf/gping · critical

Failed to create a WinPinger instance

Error message

Failed to create a WinPinger instance

What it means

This panic comes from an `.expect("Failed to create a WinPinger instance")` on `winping::Pinger::new()` inside the background thread spawned by `WindowsPinger::start()` (pinger/src/windows.rs:67). `WinPinger::new()` wraps the Windows ICMP API (`IcmpCreateFile`); when that handle cannot be created, the Result is an Err and the `expect` panics the thread. Because the panic happens in a spawned thread, `start()` still returns a receiver, but the receiver silently never yields pings and the panic message only surfaces if the thread's panic hook prints it.

Solutions

  1. Ensure the Windows pinger is only selected on Windows targets (cfg(target_os = "windows") dispatch in the library that picks the Pinger impl); on Linux/macOS use the Unix pinger instead of the winping-based one.
  2. Run on a Windows system where the ICMP (iphlpapi) facilities are available and not blocked by policy/antivirus/firewall security software.
  3. Update the winping dependency to the latest version and check its docs for known `Pinger::new()` failure modes.
  4. Patch or wrap `start()` so `WinPinger::new()` failure is returned as `PingCreationError` instead of panicking via `expect` inside the thread.
  5. Check for ICMP handle leaks: if the app creates many `WindowsPinger` instances, drop old ones so Windows can reclaim IcmpFile handles.

Example fix

// before
let pinger = WinPinger::new().expect("Failed to create a WinPinger instance");
// after
let pinger = match WinPinger::new() {
    Ok(p) => p,
    Err(e) => {
        let _ = tx.send(PingResult::Timeout(format!("WinPinger init failed: {e}")));
        return; // or propagate via a Result channel instead of panicking
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

if cfg!(not(target_os = "windows")) {
    return Err(PingCreationError::UnsupportedPlatform); // pick a Unix pinger instead
}
// On Windows, verify winping initializes before relying on start():
let probe = winping::Pinger::new().map_err(|_| PingCreationError::Other)?;

Type guard

fn winpinger_available() -> bool {
    cfg!(target_os = "windows") && winping::Pinger::new().is_ok()
}

Try / catch

// panic occurs in a spawned thread; catch at thread boundary
let rx = pinger.start()?;
let handle = thread::Builder::new()
    .spawn_scoped(scope, move || {
        let result = std::panic::catch_unwind(|| {
            // code that calls start() and reads from rx
        });
        if result.is_err() {
            eprintln!("pinger thread panicked: WinPinger::new failed");
        }
    })?;
// Or, in the consuming loop, detect a receiver that never yields:
match rx.recv_timeout(Duration::from_secs(5)) {
    Err(mpsc::RecvTimeoutError::Timeout) => eprintln!("pinger thread likely panicked at init"),
    other => other,
}

Prevention

When it happens

Trigger: Calling `WindowsPinger::start()` (via `pinger::Pinger::from_options(...)` then `.start()`) when `winping::Pinger::new()` fails: running on a non-Windows platform with the Windows code path compiled in (winping is Windows-only and its non-Windows build stubs fail), `IcmpCreateFile` failing due to ICMP support being unavailable/disabled, or resource/handle exhaustion in the process.

Common situations: Cross-compiling or running the crate on Linux/macOS while the Windows pinger gets selected (e.g. wrong cfg dispatch); Windows environments where raw ICMP is blocked by security policy, service, or sandbox (some containers, stripped-down Windows images); system handle limits exhausted after many pinger instances; older winping versions where `new()` has different failure behavior.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.


AI-assisted analysis of orf/gping@681bd79b18 (2026-09-08). Data as JSON: /api/errors/6980007b09a403c8. Report an issue: GitHub.

Appendix: source

Thrown at pinger/src/windows.rs:67

                                matches!(addr.ip(), IpAddr::V4(_))
                            }
                        })
                        .collect()
                };
                if selected_ips.is_empty() {
                    return Err(PingCreationError::HostnameError {
                        hostname: domain.clone(),
                        err: std::io::Error::other("no IPs found"),
                    });
                }
                selected_ips[0].ip()
            }
        };

        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            let pinger = WinPinger::new().expect("Failed to create a WinPinger instance");
            let mut buffer = Buffer::new();
            loop {
                match pinger.send(parsed_ip.clone(), &mut buffer) {
                    Ok(rtt) => {
                        if tx
                            .send(PingResult::Pong(
                                Duration::from_millis(rtt as u64),
                                "".to_string(),
                            ))
                            .is_err()
                        {
                            break;
                        }
                    }
                    Err(_) => {
                        // Fuck it. All errors are timeouts. Why not.
                        if tx.send(PingResult::Timeout("".to_string())).is_err() {
                            break;

View on GitHub (pinned to 681bd79b18)