firecracker-microvm/firecracker · error

TimerFd read failed

Error message

TimerFd read failed: {err:#}

What it means

Reading the underlying timerfd file descriptor inside TimerFd::read failed with an I/O error other than EAGAIN/WouldBlock (which is normally swallowed and reported as 0 expirations, since the fd is opened NONBLOCK). This means the kernel refused or failed the read — typically because the fd is invalid/closed, or an unexpected OS-level condition occurred — so the number of expirations could not be retrieved. It fires as a panic at src/utils/src/time.rs:299 whenever file.read() on the real timerfd returns any error other than WouldBlock.

Solutions

  1. Check that the timerfd was created successfully and not closed before read.
  2. Handle EAGAIN on non-blocking timerfd reads and re-arm the timer correctly.
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at src/utils/src/time.rs:252 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of firecracker-microvm/firecracker@23b09b943f (2026-09-19). Data as JSON: /api/errors/33da26fcb90905a1. Report an issue: GitHub.

Appendix: source

Thrown at src/utils/src/time.rs:299

            std::io::Error::last_os_error()
        );
    }

    /// Read the value from the timer. Since a real timer is always created with the NONBLOCK
    /// flag, this function does not block and returns `0` if the timer has not fired. For a mock
    /// timer it returns the number of expirations that have occurred (per the virtual clock)
    /// since the previous read.
    pub fn read(&mut self) -> u64 {
        let file = match self {
            TimerFd::Real(file) => file,
            #[cfg(any(test, feature = "test-utils"))]
            TimerFd::Mock(mock) => return mock.read(),
        };
        let mut buf = [0u8; size_of::<u64>()];
        match file.read(buf.as_mut_slice()) {
            Ok(_) => u64::from_ne_bytes(buf),
            Err(inner) if inner.kind() == ErrorKind::WouldBlock => 0,
            Err(err) => panic!("TimerFd read failed: {err:#}"),
        }
    }

    /// Tell if the timer is currently armed.
    pub fn is_armed(&self) -> bool {
        let file = match self {
            TimerFd::Real(file) => file,
            #[cfg(any(test, feature = "test-utils"))]
            TimerFd::Mock(mock) => return mock.is_armed(),
        };
        // SAFETY: Zero init of a PDO type.
        let mut spec: libc::itimerspec = unsafe { std::mem::zeroed() };
        // SAFETY: Safe because timerfd_gettime is trusted to only modify `spec`.
        let ret = unsafe { libc::timerfd_gettime(file.as_raw_fd(), &mut spec) };
        assert!(
            0 <= ret,
            "TimerFd arm failed: {:#}",
            std::io::Error::last_os_error()

View on GitHub (pinned to 23b09b943f)