firecracker-microvm/firecracker · error

Device is not initialized

Error message

Device is not initialized

What it means

Panic from `expect("Device is not initialized")` in `Vsock::signal_used_queue` (src/vmm/src/devices/virtio/vsock/device.rs:141). `self.device_state.active_state()` returns `Some` only after the guest virtio driver has activated the device ( FEATURES_OK/DRIVER_OK handshake completed and the device moved to Activated). If any code path signals the used queue before activation, `active_state()` is None and the process aborts.

Source

Thrown at src/vmm/src/devices/virtio/vsock/device.rs:139

        Self::with_queues(cid, backend, queues)
    }

    /// Retrieve the cid associated with this vsock device.
    pub fn cid(&self) -> u64 {
        self.cid
    }

    /// Access the backend behind the device.
    pub fn backend(&self) -> &B {
        &self.backend
    }

    /// Signal the guest driver that we've used some virtio buffers that it had previously made
    /// available.
    pub fn signal_used_queue(&self, qidx: usize) -> Result<(), DeviceError> {
        self.device_state
            .active_state()
            .expect("Device is not initialized")
            .interrupt
            .trigger(VirtioInterruptType::Queue(qidx.try_into().unwrap_or_else(
                |_| panic!("vsock: invalid queue index: {qidx}"),
            )))
            .map_err(DeviceError::FailedSignalingIrq)
    }

    /// Signal the guest which queues are ready to be consumed
    pub fn signal_used_queues(&self, used_queues: &[u16]) -> Result<(), DeviceError> {
        self.device_state
            .active_state()
            .expect("Device is not initialized")
            .interrupt
            .trigger_queues(used_queues)
            .map_err(DeviceError::FailedSignalingIrq)
    }

    /// Walk the driver-provided RX queue buffers and attempt to fill them up with any data that we

View on GitHub (pinned to 81b38b9dad)

Solutions

  1. Make sure the vsock backend event handler is only registered/started after the device receives DRIVER_OK (check `device_state.active_state().is_some()` before signaling)
  2. If restoring from a snapshot, verify the restore path calls `activate()` on the vsock device before resuming queue/event processing
  3. In library code, replace the `expect` with a graceful branch: `match self.device_state.active_state() { Some(s) => s.interrupt.trigger(..), None => { warn!(...); Ok(()) } }`
  4. If you drive the device from tests, activate it with a mock interrupt/queue pair first

Example fix

// before
self.device_state
    .active_state()
    .expect("Device is not initialized")
    .interrupt
    .trigger(VirtioInterruptType::Queue(qidx.try_into().unwrap_or_else(|_| panic!("vsock: invalid queue index: {qidx}"))))
    .map_err(DeviceError::FailedSignalingIrq)

// after
if let Some(state) = self.device_state.active_state() {
    state.interrupt
        .trigger(VirtioInterruptType::Queue(qidx as u16))
        .map_err(DeviceError::FailedSignalingIrq)
} else {
    warn!("vsock: signal_used_queue before activation (qidx {qidx})");
    Ok(())
}
Defensive patterns

Strategy: validation

Validate before calling

// Only let the backend notify queues once the guest driver activated the device
if vsock.device_state().active_state().is_some() {
    vsock.signal_used_queue(qidx)?;
} else {
    warn!("vsock not activated; deferring queue signal");
}

Type guard

fn is_vsock_activated(dev: &Vsock<impl VsockBackend>) -> bool {
    dev.device_state().active_state().is_some()
}

Try / catch

// Panics cannot be caught with Result; as a last resort isolate third-party threads:
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| vsock.signal_used_queue(0)));
if r.is_err() { /* device not initialized or irq failure: restart device */ }

Prevention

When it happens

Trigger: Calling `signal_used_queue(qidx)` (or the backend doing so indirectly) before the guest driver finished the virtio activation handshake: e.g. a host-side vsock peer connects and pushes data while the device is still in `Inactive`/`Created` state, or during snapshot-restore before `activate()` has run.

Common situations: Guest boots a kernel without a virtio-vsock driver (device never activates) while the host backend already delivers RX data; restoring from a snapshot where the backend/event handler threads start before the device is re-activated; tests that instantiate the device and drive queues directly without an activate step.

Related errors


AI-assisted analysis of firecracker-microvm/firecracker@81b38b9dad (2026-08-19). Data as JSON: /api/errors/e7fe63c5b518b10a. Report an issue: GitHub.