firecracker-microvm/firecracker · error

one-shot channel closed

Error message

one-shot channel closed

What it means

Error "one-shot channel closed" thrown in firecracker-microvm/firecracker.

Solutions

  1. Ensure the sender side of the one-shot channel is kept alive until the response is sent.
  2. Handle the closed channel as a shutdown signal and abort the pending operation cleanly.

When it happens

Trigger: Thrown at src/firecracker/src/api_server_adapter.rs:93 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at src/firecracker/src/api_server_adapter.rs:93

                .expect("Poisoned lock")
                .handle_request(event_manager);

            match vmm.lock().unwrap().shutdown_exit_code() {
                Some(FcExitCode::Ok) => break,
                Some(exit_code) => return Err(ApiServerError::MicroVMStoppedWithError(exit_code)),
                None => continue,
            }
        }
        Ok(())
    }

    fn _handle_request(&mut self, req_action: VmmAction, event_manager: &mut EventManager) {
        let response = self.controller.handle_request(req_action, event_manager);
        // Send back the result.
        self.to_api
            .send(Box::new(response))
            .map_err(|_| ())
            .expect("one-shot channel closed");
    }

    fn handle_request(&mut self, event_manager: &mut EventManager) {
        if let Some(api_request) = self.request.take() {
            let request_is_pause = *api_request == VmmAction::Pause;
            self._handle_request(*api_request, event_manager);

            // If the latest req is a pause request, temporarily switch to a mode where we
            // do blocking `recv`s on the `from_api` receiver in a loop, until we get
            // unpaused. The device emulation is implicitly paused since we do not
            // return to `run_microvm` and hence `event_manager.run()` is not called
            // again: device fds (virtqueue notifications, tap, rate limiters, timers)
            // are not polled until we break out of this loop on `Resume`.
            if request_is_pause {
                // This loop only attempts to process API requests, so things like the
                // metric flush timerfd handling are frozen as well (an explicit `FlushMetrics`
                // request still goes through).
                loop {

View on GitHub (pinned to 23b09b943f)