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
- 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.
- Run on a Windows system where the ICMP (iphlpapi) facilities are available and not blocked by policy/antivirus/firewall security software.
- Update the winping dependency to the latest version and check its docs for known `Pinger::new()` failure modes.
- Patch or wrap `start()` so `WinPinger::new()` failure is returned as `PingCreationError` instead of panicking via `expect` inside the thread.
- 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
- Only construct WindowsPinger on Windows targets; gate selection with cfg(target_os = "windows").
- Patch the library to return a Result from start() instead of using expect() in the spawned thread.
- Smoke-test WinPinger::new() at application startup on Windows before starting background ping loops.
- Avoid environments that strip ICMP support (hardened sandboxes, stripped containers) for this code path.
- Watch for handle exhaustion: reuse one pinger instance rather than creating many.
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)