shadowsocks/shadowsocks-rust · warning
errno
Error message
errno
What it means
Panic in daemonize's errno(): std::io::Error::last_os_error().raw_os_error() returned None, meaning the last OS error had no raw errno. This should be nearly impossible (raw_os_error is None only for constructed io::Errors), and expect('errno') is an internal invariant check used by check_err and execute_child when reporting daemonization failures.
Source
Thrown at src/daemonize/daemonize/error.rs:160
impl Num for i64 {
fn is_err(&self) -> bool {
*self == -1
}
}
impl Num for isize {
fn is_err(&self) -> bool {
*self == -1
}
}
pub fn check_err<N: Num, F: FnOnce(Errno) -> ErrorKind>(ret: N, f: F) -> Result<N, ErrorKind> {
if ret.is_err() { Err(f(errno())) } else { Ok(ret) }
}
pub fn errno() -> Errno {
std::io::Error::last_os_error().raw_os_error().expect("errno")
}
View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Call errno() immediately after the failing syscall, before other io operations
- Inspect preceding code that may have set a non-OS io::Error and handle it separately
- Replace expect with a fallback error kind (ErrorKind::Other) instead of panicking in a daemonization path
- Run the daemonization in the foreground with logging to capture the sequence of failing syscalls
Example fix
// before
pub fn errno() -> Errno {
std::io::Error::last_os_error().raw_os_error().expect("errno")
}
// after
pub fn errno() -> Errno {
std::io::Error::last_os_error()
.raw_os_error()
.unwrap_or(libc::EIO)
} Defensive patterns
Strategy: fallback
Validate before calling
// not applicable: errno() depends on thread-local OS state, not caller inputs
Type guard
fn last_raw_errno() -> Option<i32> {
std::io::Error::last_os_error().raw_os_error()
} Try / catch
// expect() panics cannot be caught in-process except via catch_unwind; prefer reading the errno yourself let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(libc::EIO);
Prevention
- Read last_os_error immediately after a failing syscall, before other io/FFI calls
- Avoid interleaving constructed io::Errors with syscall error reporting
- Favor unwrap_or with a default errno in diagnostic helpers
- Run daemonization flows in foreground first to surface syscall failures
When it happens
Trigger: check_err or execute_child detects a failed syscall return and calls errno(), but last_os_error() yields an io::Error whose raw_os_error() is None (non-OS io::Error active in the thread's error slot).
Common situations: A prior library call stored a custom (non-OS) io::Error in the thread-local last-error slot; interleaving with other FFI/io code that clobbers the last error between syscall failure and errno() read.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- cannot get current working directory, {err:?}
- cannot get absolute path to working directory, {err:?}
- missing manager config
- SockAddr.as_socket
- iface
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/31bbd3504cb8397e.
Report an issue: GitHub.