Repository: cloud-hypervisor/cloud-hypervisor
Pull request #7061: DeviceManagerError: Implement Error including all Variants
Author: login: phip1611
Created: 2025-05-13T14:47:58Z | Merged: 2025-05-16T12:28:43Z

**EDIT**: This is a prerequisite for #7066. To have smaller PRs, this is a split-out.

The DeviceManagerError type is among the types missing the `Error` trait so
far. To streamline the code and to simplify usage on higher levels of this
error type, this type now implements Display and Error.

As not all variant values are Error yet, `#[source]` is not everywhere where
it could be. This is done in the next commits.

The high level goal is: Enable future work to improve the error output of
cloud hypervisor.




Diff:
diff --git a/pci/src/bus.rs b/pci/src/bus.rs
index e5fe38f22d..602dd1c2e1 100644
--- a/pci/src/bus.rs
+++ b/pci/src/bus.rs
@@ -10,6 +10,7 @@ use std::ops::DerefMut;
 use std::sync::{Arc, Barrier, Mutex};
 
 use byteorder::{ByteOrder, LittleEndian};
+use thiserror::Error;
 use vm_device::{Bus, BusDevice, BusDeviceSync};
 
 use crate::configuration::{
@@ -23,21 +24,28 @@ const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
 const NUM_DEVICE_IDS: usize = 32;
 
 /// Errors for device manager.
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum PciRootError {
     /// Could not allocate device address space for the device.
-    AllocateDeviceAddrs(PciDeviceError),
+    #[error("Could not allocate device address space for the device: {0}")]
+    AllocateDeviceAddrs(#[source] PciDeviceError),
     /// Could not allocate an IRQ number.
+    #[error("Could not allocate an IRQ number")]
     AllocateIrq,
     /// Could not add a device to the port io bus.
-    PioInsert(vm_device::BusError),
+    #[error("Could not add a device to the port io bus: {0}")]
+    PioInsert(#[source] vm_device::BusError),
     /// Could not add a device to the mmio bus.
-    MmioInsert(vm_device::BusError),
+    #[error("Could not add a device to the mmio bus: {0}")]
+    MmioInsert(#[source] vm_device::BusError),
     /// Could not find an available device slot on the PCI bus.
+    #[error("Could not find an available device slot on the PCI bus")]
     NoPciDeviceSlotAvailable,
     /// Invalid PCI device identifier provided.
+    #[error("Invalid PCI device identifier provided")]
     InvalidPciDeviceSlot(usize),
     /// Valid PCI device identifier but already used.
+    #[error("Valid PCI device identifier but already used")]
     AlreadyInUsePciDeviceSlot(usize),
 }
 pub type Result<T> = std::result::Result<T, PciRootError>;
diff --git a/pci/src/configuration.rs b/pci/src/configuration.rs
index 036894d8bf..7264f7caf1 100644
--- a/pci/src/configuration.rs
+++ b/pci/src/configuration.rs
@@ -4,11 +4,11 @@
 //
 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
 
-use std::fmt::{self, Display};
 use std::sync::{Arc, Mutex};
 
 use byteorder::{ByteOrder, LittleEndian};
 use serde::{Deserialize, Serialize};
+use thiserror::Error;
 use vm_device::PciBarType;
 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
 
@@ -493,60 +493,45 @@ pub struct PciBarConfiguration {
     prefetchable: PciBarPrefetchable,
 }
 
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum Error {
+    #[error("address {0} size {1} too big")]
     BarAddressInvalid(u64, u64),
+    #[error("bar {0} already used")]
     BarInUse(usize),
+    #[error("64bit bar {0} already used (requires two regs)")]
     BarInUse64(usize),
+    #[error("bar {0} invalid, max {max}", max = NUM_BAR_REGS - 1)]
     BarInvalid(usize),
+    #[error("64bitbar {0} invalid, requires two regs, max {max}", max = NUM_BAR_REGS - 1)]
     BarInvalid64(usize),
+    #[error("bar address {0} not a power of two")]
     BarSizeInvalid(u64),
+    #[error("empty capabilities are invalid")]
     CapabilityEmpty,
+    #[error("Invalid capability length {0}")]
     CapabilityLengthInvalid(usize),
+    #[error("capability of size {0} doesn't fit")]
     CapabilitySpaceFull(usize),
+    #[error("failed to decode 32 bits BAR size")]
     Decode32BarSize,
+    #[error("failed to decode 64 bits BAR size")]
     Decode64BarSize,
+    #[error("failed to encode 32 bits BAR size")]
     Encode32BarSize,
+    #[error("failed to encode 64 bits BAR size")]
     Encode64BarSize,
+    #[error("address {0} size {1} too big")]
     RomBarAddressInvalid(u64, u64),
+    #[error("rom bar {0} already used")]
     RomBarInUse(usize),
+    #[error("rom bar {0} invalid, max {max}", max = NUM_BAR_REGS - 1)]
     RomBarInvalid(usize),
+    #[error("rom bar address {0} not a power of two")]
     RomBarSizeInvalid(u64),
 }
 pub type Result<T> = std::result::Result<T, Error>;
 
-impl std::error::Error for Error {}
-
-impl Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-        match self {
-            BarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
-            BarInUse(b) => write!(f, "bar {b} already used"),
-            BarInUse64(b) => write!(f, "64bit bar {b} already used(requires two regs)"),
-            BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
-            BarInvalid64(b) => write!(
-                f,
-                "64bitbar {} invalid, requires two regs, max {}",
-                b,
-                NUM_BAR_REGS - 1
-            ),
-            BarSizeInvalid(s) => write!(f, "bar address {s} not a power of two"),
-            CapabilityEmpty => write!(f, "empty capabilities are invalid"),
-            CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {l}"),
-            CapabilitySpaceFull(s) => write!(f, "capability of size {s} doesn't fit"),
-            Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
-            Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
-            Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
-            Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
-            RomBarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
-            RomBarInUse(b) => write!(f, "rom bar {b} already used"),
-            RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
-            RomBarSizeInvalid(s) => write!(f, "rom bar address {s} not a power of two"),
-        }
-    }
-}
-
 impl PciConfiguration {
     #[allow(clippy::too_many_arguments)]
     pub fn new(
diff --git a/pci/src/device.rs b/pci/src/device.rs
index 0bc84208d5..782958c752 100644
--- a/pci/src/device.rs
+++ b/pci/src/device.rs
@@ -5,49 +5,36 @@
 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
 
 use std::any::Any;
-use std::fmt::{self, Display};
 use std::sync::{Arc, Barrier, Mutex};
 use std::{io, result};
 
+use thiserror::Error;
 use vm_allocator::{AddressAllocator, SystemAllocator};
 use vm_device::Resource;
 
 use crate::configuration::{self, PciBarRegionType};
 use crate::PciBarConfiguration;
 
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum Error {
     /// Setup of the device capabilities failed.
-    CapabilitiesSetup(configuration::Error),
+    #[error("Setup of the device capabilities failed: {0}")]
+    CapabilitiesSetup(#[source] configuration::Error),
     /// Allocating space for an IO BAR failed.
+    #[error("Allocating space for an IO BAR failed")]
     IoAllocationFailed(u64),
     /// Registering an IO BAR failed.
-    IoRegistrationFailed(u64, configuration::Error),
+    #[error("Registering an IO BAR failed: {0}")]
+    IoRegistrationFailed(u64, #[source] configuration::Error),
     /// Expected resource not found.
+    #[error("Expected resource not found")]
     MissingResource,
     /// Invalid resource.
+    #[error("Invalid resource: {0:?}")]
     InvalidResource(Resource),
 }
 pub type Result<T> = std::result::Result<T, Error>;
 
-impl Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-
-        match self {
-            CapabilitiesSetup(e) => write!(f, "failed to add capability {e}"),
-            IoAllocationFailed(size) => {
-                write!(f, "failed to allocate space for an IO BAR, size={size}")
-            }
-            IoRegistrationFailed(addr, e) => {
-                write!(f, "failed to register an IO BAR, addr={addr} err={e}")
-            }
-            MissingResource => write!(f, "failed to find expected resource"),
-            InvalidResource(r) => write!(f, "invalid resource {r:?}"),
-        }
-    }
-}
-
 #[derive(Clone, Copy, Debug)]
 pub struct BarReprogrammingParams {
     pub old_base: u64,
diff --git a/virtio-devices/src/vsock/unix/mod.rs b/virtio-devices/src/vsock/unix/mod.rs
index b83d96c156..6250e41e97 100644
--- a/virtio-devices/src/vsock/unix/mod.rs
+++ b/virtio-devices/src/vsock/unix/mod.rs
@@ -14,6 +14,7 @@ mod muxer_killq;
 mod muxer_rxq;
 
 pub use muxer::VsockMuxer as VsockUnixBackend;
+use thiserror::Error;
 pub use Error as VsockUnixError;
 
 mod defs {
@@ -27,29 +28,40 @@ mod defs {
     pub const MUXER_KILLQ_SIZE: usize = 128;
 }
 
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum Error {
     /// Error converting from UTF-8
-    ConvertFromUtf8(std::str::Utf8Error),
+    #[error("Error converting from UTF-8: {0}")]
+    ConvertFromUtf8(#[source] std::str::Utf8Error),
     /// Error registering a new epoll-listening FD.
-    EpollAdd(std::io::Error),
+    #[error("Error registering a new epoll-listening FD: {0}")]
+    EpollAdd(#[source] std::io::Error),
     /// Error creating an epoll FD.
-    EpollFdCreate(std::io::Error),
+    #[error("Error creating an epoll FD: {0}")]
+    EpollFdCreate(#[source] std::io::Error),
     /// The host made an invalid vsock port connection request.
+    #[error("The host made an invalid vsock port connection request")]
     InvalidPortRequest,
     /// Error parsing integer.
-    ParseInteger(std::num::ParseIntError),
+    #[error("Error parsing integer: {0}")]
+    ParseInteger(#[source] std::num::ParseIntError),
     /// Error reading stream port.
-    ReadStreamPort(Box<Error>),
+    #[error("Error reading stream port: {0}")]
+    ReadStreamPort(#[source] Box<Error>),
     /// Error accepting a new connection from the host-side Unix socket.
-    UnixAccept(std::io::Error),
+    #[error("Error accepting a new connection from the host-side Unix socket: {0}")]
+    UnixAccept(#[source] std::io::Error),
     /// Error binding to the host-side Unix socket.
-    UnixBind(std::io::Error),
+    #[error("Error binding to the host-side Unix socket: {0}")]
+    UnixBind(#[source] std::io::Error),
     /// Error connecting to a host-side Unix socket.
-    UnixConnect(std::io::Error),
+    #[error("Error connecting to a host-side Unix socket: {0}")]
+    UnixConnect(#[source] std::io::Error),
     /// Error reading from host-side Unix socket.
-    UnixRead(std::io::Error),
+    #[error("Error reading from host-side Unix socket: {0}")]
+    UnixRead(#[source] std::io::Error),
     /// Muxer connection limit reached.
+    #[error("Muxer connection limit reached")]
     TooManyConnections,
 }
 
diff --git a/vm-device/src/bus.rs b/vm-device/src/bus.rs
index ff7c1f8c50..70bbc049a4 100644
--- a/vm-device/src/bus.rs
+++ b/vm-device/src/bus.rs
@@ -10,7 +10,9 @@
 use std::cmp::Ordering;
 use std::collections::btree_map::BTreeMap;
 use std::sync::{Arc, Barrier, Mutex, RwLock, Weak};
-use std::{convert, error, fmt, io, result};
+use std::{convert, io, result};
+
+use thiserror::Error;
 
 /// Trait for devices that respond to reads or writes in an arbitrary address space.
 ///
@@ -51,26 +53,21 @@ impl<B: BusDevice> BusDeviceSync for Mutex<B> {
     }
 }
 
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum Error {
     /// The insertion failed because the new device overlapped with an old device.
+    #[error("The insertion failed because the new device overlapped with an old device")]
     Overlap,
     /// Failed to operate on zero sized range.
+    #[error("Failed to operate on zero sized range")]
     ZeroSizedRange,
     /// Failed to find address range.
+    #[error("Failed to find address range")]
     MissingAddressRange,
 }
 
 pub type Result<T> = result::Result<T, Error>;
 
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "bus_error: {self:?}")
-    }
-}
-
-impl error::Error for Error {}
-
 impl convert::From<Error> for io::Error {
     fn from(e: Error) -> Self {
         io::Error::other(e)
diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs
index adf4d26ac3..d228010c03 100644
--- a/vmm/src/device_manager.rs
+++ b/vmm/src/device_manager.rs
@@ -74,6 +74,7 @@ use pci::{
 use rate_limiter::group::RateLimiterGroup;
 use seccompiler::SeccompAction;
 use serde::{Deserialize, Serialize};
+use thiserror::Error;
 use tracer::trace_scoped;
 use vfio_ioctls::{VfioContainer, VfioDevice, VfioDeviceFd};
 use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, VirtioTransport};
@@ -147,379 +148,502 @@ const VFIO_USER_DEVICE_NAME_PREFIX: &str = "_vfio_user";
 const VIRTIO_PCI_DEVICE_NAME_PREFIX: &str = "_virtio-pci";
 
 /// Errors associated with device manager
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum DeviceManagerError {
     /// Cannot create EventFd.
-    EventFd(io::Error),
+    #[error("Cannot create EventFd: {0}")]
+    EventFd(#[source] io::Error),
 
     /// Cannot open disk path
-    Disk(io::Error),
+    #[error("Cannot open disk path: {0}")]
+    Disk(#[source] io::Error),
 
     /// Cannot create vhost-user-net device
-    CreateVhostUserNet(virtio_devices::vhost_user::Error),
+    #[error("Cannot create vhost-user-net device: {0}")]
+    CreateVhostUserNet(#[source] virtio_devices::vhost_user::Error),
 
     /// Cannot create virtio-blk device
-    CreateVirtioBlock(io::Error),
+    #[error("Cannot create virtio-blk device: {0}")]
+    CreateVirtioBlock(#[source] io::Error),
 
     /// Cannot create virtio-net device
-    CreateVirtioNet(virtio_devices::net::Error),
+    #[error("Cannot create virtio-net device: {0}")]
+    CreateVirtioNet(#[source] virtio_devices::net::Error),
 
     /// Cannot create virtio-console device
-    CreateVirtioConsole(io::Error),
+    #[error("Cannot create virtio-console device: {0}")]
+    CreateVirtioConsole(#[source] io::Error),
 
     /// Cannot create virtio-rng device
-    CreateVirtioRng(io::Error),
+    #[error("Cannot create virtio-rng device: {0}")]
+    CreateVirtioRng(#[source] io::Error),
 
     /// Cannot create virtio-fs device
-    CreateVirtioFs(virtio_devices::vhost_user::Error),
+    #[error("Cannot create virtio-fs device: {0}")]
+    CreateVirtioFs(#[source] virtio_devices::vhost_user::Error),
 
     /// Virtio-fs device was created without a socket.
+    #[error("Virtio-fs device was created without a socket")]
     NoVirtioFsSock,
 
     /// Cannot create vhost-user-blk device
-    CreateVhostUserBlk(virtio_devices::vhost_user::Error),
+    #[error("Cannot create vhost-user-blk device: {0}")]
+    CreateVhostUserBlk(#[source] virtio_devices::vhost_user::Error),
 
     /// Cannot create virtio-pmem device
-    CreateVirtioPmem(io::Error),
+    #[error("Cannot create virtio-pmem device: {0}")]
+    CreateVirtioPmem(#[source] io::Error),
 
     /// Cannot create vDPA device
-    CreateVdpa(virtio_devices::vdpa::Error),
+    #[error("Cannot create vdpa device: {0}")]
+    CreateVdpa(#[source] virtio_devices::vdpa::Error),
 
     /// Cannot create virtio-vsock device
-    CreateVirtioVsock(io::Error),
+    #[error("Cannot create virtio-vsock device: {0}")]
+    CreateVirtioVsock(#[source] io::Error),
 
     /// Cannot create tpm device
-    CreateTpmDevice(anyhow::Error),
+    #[error("Cannot create tmp device: {0}")]
+    CreateTpmDevice(#[source] anyhow::Error),
 
     /// Failed to convert Path to &str for the vDPA device.
+    #[error("Failed to convert Path to &str for the vDPA device")]
     CreateVdpaConvertPath,
 
     /// Failed to convert Path to &str for the virtio-vsock device.
+    #[error("Failed to convert Path to &str for the virtio-vsock device")]
     CreateVsockConvertPath,
 
     /// Cannot create virtio-vsock backend
-    CreateVsockBackend(virtio_devices::vsock::VsockUnixError),
+    #[error("Cannot create virtio-vsock backend: {0}")]
+    CreateVsockBackend(#[source] virtio_devices::vsock::VsockUnixError),
 
     /// Cannot create virtio-iommu device
-    CreateVirtioIommu(io::Error),
+    #[error("Cannot create virtio-iommu device: {0}")]
+    CreateVirtioIommu(#[source] io::Error),
 
     /// Cannot create virtio-balloon device
-    CreateVirtioBalloon(io::Error),
+    #[error("Cannot create virtio-balloon device: {0}")]
+    CreateVirtioBalloon(#[source] io::Error),
 
     /// Cannot create pvmemcontrol device
     #[cfg(feature = "pvmemcontrol")]
-    CreatePvmemcontrol(io::Error),
+    #[error("Cannot create pvmemcontrol device: {0}")]
+    CreatePvmemcontrol(#[source] io::Error),
 
     /// Cannot create virtio-watchdog device
-    CreateVirtioWatchdog(io::Error),
+    #[error("Cannot create virtio-watchdog device: {0}")]
+    CreateVirtioWatchdog(#[source] io::Error),
 
     /// Failed to parse disk image format
-    DetectImageType(io::Error),
+    #[error("Failed to parse disk image format: {0}")]
+    DetectImageType(#[source] io::Error),
 
     /// Cannot open qcow disk path
-    QcowDeviceCreate(qcow::Error),
+    #[error("Cannot open qcow disk path: {0}")]
+    QcowDeviceCreate(#[source] qcow::Error),
 
     /// Cannot create serial manager
-    CreateSerialManager(SerialManagerError),
+    #[error("Cannot create serial manager: {0}")]
+    CreateSerialManager(#[source] SerialManagerError),
 
     /// Cannot spawn the serial manager thread
-    SpawnSerialManager(SerialManagerError),
+    #[error("Cannot spawn serial manager thread: {0}")]
+    SpawnSerialManager(#[source] SerialManagerError),
 
     /// Cannot open tap interface
-    OpenTap(net_util::TapError),
+    #[error("Cannot open tap interface: {0}")]
+    OpenTap(#[source] net_util::TapError),
 
     /// Cannot allocate IRQ.
+    #[error("Cannot allocate IRQ")]
     AllocateIrq,
 
     /// Cannot configure the IRQ.
-    Irq(vmm_sys_util::errno::Error),
+    #[error("Cannot configure the IRQ: {0}")]
+    Irq(#[source] vmm_sys_util::errno::Error),
 
     /// Cannot allocate PCI BARs
-    AllocateBars(pci::PciDeviceError),
+    #[error("Cannot allocate PCI BARs: {0}")]
+    AllocateBars(#[source] pci::PciDeviceError),
 
     /// Could not free the BARs associated with a PCI device.
-    FreePciBars(pci::PciDeviceError),
+    #[error("Could not free the BARs associated with a PCI device: {0}")]
+    FreePciBars(#[source] pci::PciDeviceError),
 
     /// Cannot register ioevent.
-    RegisterIoevent(anyhow::Error),
+    #[error("Cannot register ioevent: {0}")]
+    RegisterIoevent(#[source] anyhow::Error),
 
     /// Cannot unregister ioevent.
-    UnRegisterIoevent(anyhow::Error),
+    #[error("Cannot unregister ioevent: {0}")]
+    UnRegisterIoevent(#[source] anyhow::Error),
 
     /// Cannot create virtio device
-    VirtioDevice(virtio_devices::transport::VirtioPciDeviceError),
+    #[error("Cannot create virtio device: {0}")]
+    VirtioDevice(#[source] virtio_devices::transport::VirtioPciDeviceError),
 
     /// Cannot add PCI device
-    AddPciDevice(pci::PciRootError),
+    #[error("Cannot add PCI device: {0}")]
+    AddPciDevice(#[source] pci::PciRootError),
 
     /// Cannot open persistent memory file
-    PmemFileOpen(io::Error),
+    #[error("Cannot open persistent memory file: {0}")]
+    PmemFileOpen(#[source] io::Error),
 
     /// Cannot set persistent memory file size
-    PmemFileSetLen(io::Error),
+    #[error("Cannot set persistent memory file size: {0}")]
+    PmemFileSetLen(#[source] io::Error),
 
     /// Cannot find a memory range for persistent memory
+    #[error("Cannot find a memory range for persistent memory")]
     PmemRangeAllocation,
 
     /// Cannot find a memory range for virtio-fs
+    #[error("Cannot find a memory range for virtio-fs")]
     FsRangeAllocation,
 
     /// Error creating serial output file
-    SerialOutputFileOpen(io::Error),
+    #[error("Error creating serial output file: {0}")]
+    SerialOutputFileOpen(#[source] io::Error),
 
-    #[cfg(target_arch = "x86_64")]
     /// Error creating debug-console output file
-    DebugconOutputFileOpen(io::Error),
+    #[cfg(target_arch = "x86_64")]
+    #[error("Error creating debug-console output file: {0}")]
+    DebugconOutputFileOpen(#[source] io::Error),
 
     /// Error creating console output file
-    ConsoleOutputFileOpen(io::Error),
+    #[error("Error creating console output file: {0}")]
+    ConsoleOutputFileOpen(#[source] io::Error),
 
     /// Error creating serial pty
-    SerialPtyOpen(io::Error),
+    #[error("Error creating serial pty: {0}")]
+    SerialPtyOpen(#[source] io::Error),
 
     /// Error creating console pty
-    ConsolePtyOpen(io::Error),
+    #[error("Error creating console pty: {0}")]
+    ConsolePtyOpen(#[source] io::Error),
 
-    /// Error creating console pty
-    DebugconPtyOpen(io::Error),
+    /// Error creating debugcon pty
+    #[error("Error creating console pty: {0}")]
+    DebugconPtyOpen(#[source] io::Error),
 
     /// Error setting pty raw mode
-    SetPtyRaw(ConsoleDeviceError),
+    #[error("Error setting pty raw mode: {0}")]
+    SetPtyRaw(#[source] ConsoleDeviceError),
 
     /// Error getting pty peer
-    GetPtyPeer(vmm_sys_util::errno::Error),
+    #[error("Error getting pty peer: {0}")]
+    GetPtyPeer(#[source] vmm_sys_util::errno::Error),
 
     /// Cannot create a VFIO device
-    VfioCreate(vfio_ioctls::VfioError),
+    #[error("Cannot create a VFIO device: {0}")]
+    VfioCreate(#[source] vfio_ioctls::VfioError),
 
     /// Cannot create a VFIO PCI device
-    VfioPciCreate(pci::VfioPciError),
+    #[error("Cannot create a VFIO PCI device: {0}")]
+    VfioPciCreate(#[source] pci::VfioPciError),
 
     /// Failed to map VFIO MMIO region.
-    VfioMapRegion(pci::VfioPciError),
+    #[error("Failed to map VFIO MMIO region: {0}")]
+    VfioMapRegion(#[source] pci::VfioPciError),
 
     /// Failed to DMA map VFIO device.
-    VfioDmaMap(vfio_ioctls::VfioError),
+    #[error("Failed to DMA map VFIO device: {0}")]
+    VfioDmaMap(#[source] vfio_ioctls::VfioError),
 
     /// Failed to DMA unmap VFIO device.
-    VfioDmaUnmap(pci::VfioPciError),
+    #[error("Failed to DMA unmap VFIO device: {0}")]
+    VfioDmaUnmap(#[source] pci::VfioPciError),
 
     /// Failed to create the passthrough device.
-    CreatePassthroughDevice(anyhow::Error),
+    #[error("Failed to create the passthrough device: {0}")]
+    CreatePassthroughDevice(#[source] anyhow::Error),
 
     /// Failed to memory map.
-    Mmap(io::Error),
+    #[error("Failed to memory map: {0}")]
+    Mmap(#[source] io::Error),
 
     /// Cannot add legacy device to Bus.
-    BusError(vm_device::BusError),
+    #[error("Cannot add legacy device to Bus: {0}")]
+    BusError(#[source] vm_device::BusError),
 
     /// Failed to allocate IO port
+    #[error("Failed to allocate IO port")]
     AllocateIoPort,
 
     /// Failed to allocate MMIO address
+    #[error("Failed to allocate MMIO address")]
     AllocateMmioAddress,
 
     /// Failed to make hotplug notification
-    HotPlugNotification(io::Error),
+    #[error("Failed to make hotplug notification: {0}")]
+    HotPlugNotification(#[source] io::Error),
 
     /// Error from a memory manager operation
-    MemoryManager(MemoryManagerError),
+    #[error("Error from a memory manager operation: {0}")]
+    MemoryManager(#[source] MemoryManagerError),
 
     /// Failed to create new interrupt source group.
-    CreateInterruptGroup(io::Error),
+    #[error("Failed to create new interrupt source group: {0}")]
+    CreateInterruptGroup(#[source] io::Error),
 
     /// Failed to update interrupt source group.
-    UpdateInterruptGroup(io::Error),
+    #[error("Failed to update interrupt source group: {0}")]
+    UpdateInterruptGroup(#[source] io::Error),
 
     /// Failed to create interrupt controller.
-    CreateInterruptController(interrupt_controller::Error),
+    #[error("Failed to create interrupt controller: {0}")]
+    CreateInterruptController(#[source] interrupt_controller::Error),
 
     /// Failed to create a new MmapRegion instance.
-    NewMmapRegion(vm_memory::mmap::MmapRegionError),
+    #[error("Failed to create a new MmapRegion instance: {0}")]
+    NewMmapRegion(#[source] vm_memory::mmap::MmapRegionError),
 
     /// Failed to clone a File.
-    CloneFile(io::Error),
+    #[error("Failed to clone a File")]
+    CloneFile(#[source] io::Error),
 
     /// Failed to create socket file
-    CreateSocketFile(io::Error),
+    #[error("Failed to create socket file: {0}")]
+    CreateSocketFile(#[source] io::Error),
 
     /// Failed to spawn the network backend
-    SpawnNetBackend(io::Error),
+    #[error("Failed to spawn the network backend: {0}")]
+    SpawnNetBackend(#[source] io::Error),
 
     /// Failed to spawn the block backend
-    SpawnBlockBackend(io::Error),
+    #[error("Failed to spawn the block backend: {0}")]
+    SpawnBlockBackend(#[source] io::Error),
 
     /// Missing PCI bus.
+    #[error("Missing PCI bus")]
     NoPciBus,
 
     /// Could not find an available device name.
+    #[error("Could not find an available device name")]
     NoAvailableDeviceName,
 
     /// Missing PCI device.
+    #[error("Missing PCI device")]
     MissingPciDevice,
 
     /// Failed to remove a PCI device from the PCI bus.
-    RemoveDeviceFromPciBus(pci::PciRootError),
+    #[error("Failed to remove a PCI device from the PCI bus: {0}")]
+    RemoveDeviceFromPciBus(#[source] pci::PciRootError),
 
     /// Failed to remove a bus device from the IO bus.
-    RemoveDeviceFromIoBus(vm_device::BusError),
+    #[error("Failed to remove a bus device from the IO bus: {0}")]
+    RemoveDeviceFromIoBus(#[source] vm_device::BusError),
 
     /// Failed to remove a bus device from the MMIO bus.
-    RemoveDeviceFromMmioBus(vm_device::BusError),
+    #[error("Failed to remove a bus device from the MMIO bus: {0}")]
+    RemoveDeviceFromMmioBus(#[source] vm_device::BusError),
 
     /// Failed to find the device corresponding to a specific PCI b/d/f.
+    #[error("Failed to find the device corresponding to a specific PCI b/d/f")]
     UnknownPciBdf(u32),
 
     /// Not allowed to remove this type of device from the VM.
+    #[error("Not allowed to remove this type of device from the VM: {0}")]
     RemovalNotAllowed(vm_virtio::VirtioDeviceType),
 
     /// Failed to find device corresponding to the given identifier.
+    #[error("Failed to find device corresponding to the given identifier")]
     UnknownDeviceId(String),
 
     /// Failed to find an available PCI device ID.
-    NextPciDeviceId(pci::PciRootError),
+    #[error("Failed to find an available PCI device ID: {0}")]
+    NextPciDeviceId(#[source] pci::PciRootError),
 
     /// Could not reserve the PCI device ID.
-    GetPciDeviceId(pci::PciRootError),
+    #[error("Could not reserve the PCI device ID: {0}")]
+    GetPciDeviceId(#[source] pci::PciRootError),
 
     /// Could not give the PCI device ID back.
-    PutPciDeviceId(pci::PciRootError),
+    #[error("Could not give the PCI device ID back: {0}")]
+    PutPciDeviceId(#[source] pci::PciRootError),
 
     /// No disk path was specified when one was expected
+    #[error("No disk path was specified when one was expected")]
     NoDiskPath,
 
     /// Failed to update guest memory for virtio device.
-    UpdateMemoryForVirtioDevice(virtio_devices::Error),
+    #[error("Failed to update guest memory for virtio device: {0}")]
+    UpdateMemoryForVirtioDevice(#[source] virtio_devices::Error),
 
     /// Cannot create virtio-mem device
-    CreateVirtioMem(io::Error),
+    #[error("Cannot create virtio-mem device: {0}")]
+    CreateVirtioMem(#[source] io::Error),
 
     /// Cannot find a memory range for virtio-mem memory
+    #[error("Cannot find a memory range for virtio-mem memory")]
     VirtioMemRangeAllocation,
 
     /// Failed to update guest memory for VFIO PCI device.
-    UpdateMemoryForVfioPciDevice(vfio_ioctls::VfioError),
+    #[error("Failed to update guest memory for VFIO PCI device: {0}")]
+    UpdateMemoryForVfioPciDevice(#[source] vfio_ioctls::VfioError),
 
     /// Trying to use a directory for pmem but no size specified
+    #[error("Trying to use a directory for pmem but no size specified")]
     PmemWithDirectorySizeMissing,
 
     /// Trying to use a size that is not multiple of 2MiB
+    #[error("Trying to use a size that is not multiple of 2MiB")]
     PmemSizeNotAligned,
 
     /// Could not find the node in the device tree.
+    #[error("Could not find the node in the device tree")]
     MissingNode,
 
     /// Resource was already found.
+    #[error("Resource was already found")]
     ResourceAlreadyExists,
 
     /// Expected resources for virtio-pmem could not be found.
+    #[error("Expected resources for virtio-pmem could not be found")]
     MissingVirtioPmemResources,
 
     /// Missing PCI b/d/f from the DeviceNode.
+    #[error("Missing PCI b/d/f from the DeviceNode")]
     MissingDeviceNodePciBdf,
 
     /// No support for device passthrough
+    #[error("No support for device passthrough")]
     NoDevicePassthroughSupport,
 
     /// No socket option support for console device
+    #[error("No socket option support for console device")]
     NoSocketOptionSupportForConsoleDevice,
 
     /// Failed to resize virtio-balloon
-    VirtioBalloonResize(virtio_devices::balloon::Error),
+    #[error("Failed to resize virtio-balloon: {0}")]
+    VirtioBalloonResize(#[source] virtio_devices::balloon::Error),
 
     /// Missing virtio-balloon, can't proceed as expected.
+    #[error("Missing virtio-balloon, can't proceed as expected")]
     MissingVirtioBalloon,
 
     /// Missing virtual IOMMU device
+    #[error("Missing virtual IOMMU device")]
     MissingVirtualIommu,
 
     /// Failed to do power button notification
-    PowerButtonNotification(io::Error),
+    #[error("Failed to do power button notification: {0}")]
+    PowerButtonNotification(#[source] io::Error),
 
     /// Failed to do AArch64 GPIO power button notification
     #[cfg(target_arch = "aarch64")]
-    AArch64PowerButtonNotification(devices::legacy::GpioDeviceError),
+    #[error("Failed to do AArch64 GPIO power button notification: {0}")]
+    AArch64PowerButtonNotification(#[source] devices::legacy::GpioDeviceError),
 
     /// Failed to set O_DIRECT flag to file descriptor
+    #[error("Failed to set O_DIRECT flag to file descriptor")]
     SetDirectIo,
 
     /// Failed to create FixedVhdDiskAsync
-    CreateFixedVhdDiskAsync(io::Error),
+    #[error("Failed to create FixedVhdDiskAsync: {0}")]
+    CreateFixedVhdDiskAsync(#[source] io::Error),
 
     /// Failed to create FixedVhdDiskSync
-    CreateFixedVhdDiskSync(io::Error),
+    #[error("Failed to create FixedVhdDiskSync: {0}")]
+    CreateFixedVhdDiskSync(#[source] io::Error),
 
     /// Failed to create QcowDiskSync
-    CreateQcowDiskSync(qcow::Error),
+    #[error("Failed to create QcowDiskSync: {0}")]
+    CreateQcowDiskSync(#[source] qcow::Error),
 
     /// Failed to create FixedVhdxDiskSync
-    CreateFixedVhdxDiskSync(vhdx::VhdxError),
+    #[error("Failed to create FixedVhdxDiskSync: {0}")]
+    CreateFixedVhdxDiskSync(#[source] vhdx::VhdxError),
 
     /// Failed to add DMA mapping handler to virtio-mem device.
-    AddDmaMappingHandlerVirtioMem(virtio_devices::mem::Error),
+    #[error("Failed to add DMA mapping handler to virtio-mem device: {0}")]
+    AddDmaMappingHandlerVirtioMem(#[source] virtio_devices::mem::Error),
 
     /// Failed to remove DMA mapping handler from virtio-mem device.
-    RemoveDmaMappingHandlerVirtioMem(virtio_devices::mem::Error),
+    #[error("Failed to remove DMA mapping handler from virtio-mem device: {0}")]
+    RemoveDmaMappingHandlerVirtioMem(#[source] virtio_devices::mem::Error),
 
     /// Failed to create vfio-user client
-    VfioUserCreateClient(vfio_user::Error),
+    #[error("Failed to create vfio-user client: {0}")]
+    VfioUserCreateClient(#[source] vfio_user::Error),
 
     /// Failed to create VFIO user device
-    VfioUserCreate(VfioUserPciDeviceError),
+    #[error("Failed to create VFIO user device: {0}")]
+    VfioUserCreate(#[source] VfioUserPciDeviceError),
 
     /// Failed to map region from VFIO user device into guest
-    VfioUserMapRegion(VfioUserPciDeviceError),
+    #[error("Failed to map region from VFIO user device into guest: {0}")]
+    VfioUserMapRegion(#[source] VfioUserPciDeviceError),
 
     /// Failed to DMA map VFIO user device.
-    VfioUserDmaMap(VfioUserPciDeviceError),
+    #[error("Failed to DMA map VFIO user device: {0}")]
+    VfioUserDmaMap(#[source] VfioUserPciDeviceError),
 
     /// Failed to DMA unmap VFIO user device.
-    VfioUserDmaUnmap(VfioUserPciDeviceError),
+    #[error("Failed to DMA unmap VFIO user device: {0}")]
+    VfioUserDmaUnmap(#[source] VfioUserPciDeviceError),
 
     /// Failed to update memory mappings for VFIO user device
-    UpdateMemoryForVfioUserPciDevice(VfioUserPciDeviceError),
+    #[error("Failed to update memory mappings for VFIO user device: {0}")]
+    UpdateMemoryForVfioUserPciDevice(#[source] VfioUserPciDeviceError),
 
     /// Cannot duplicate file descriptor
-    DupFd(vmm_sys_util::errno::Error),
+    #[error("Cannot duplicate file descriptor: {0}")]
+    DupFd(#[source] vmm_sys_util::errno::Error),
 
     /// Failed to DMA map virtio device.
-    VirtioDmaMap(std::io::Error),
+    #[error("Failed to DMA map virtio device: {0}")]
+    VirtioDmaMap(#[source] std::io::Error),
 
     /// Failed to DMA unmap virtio device.
-    VirtioDmaUnmap(std::io::Error),
+    #[error("Failed to DMA unmap virtio device: {0}")]
+    VirtioDmaUnmap(#[source] std::io::Error),
 
     /// Cannot hotplug device behind vIOMMU
+    #[error("Cannot hotplug device behind vIOMMU")]
     InvalidIommuHotplug,
 
     /// Invalid identifier as it is not unique.
+    #[error("Invalid identifier as it is not unique: {0}")]
     IdentifierNotUnique(String),
 
     /// Invalid identifier
+    #[error("Invalid identifier: {0}")]
     InvalidIdentifier(String),
 
     /// Error activating virtio device
-    VirtioActivate(ActivateError),
+    #[error("Error activating virtio device: {0}")]
+    VirtioActivate(#[source] ActivateError),
 
     /// Failed retrieving device state from snapshot
-    RestoreGetState(MigratableError),
+    #[error("Failed retrieving device state from snapshot: {0}")]
+    RestoreGetState(#[source] MigratableError),
 
     /// Cannot create a PvPanic device
-    PvPanicCreate(devices::pvpanic::PvPanicError),
+    #[error("Cannot create a PvPanic device: {0}")]
+    PvPanicCreate(#[source] devices::pvpanic::PvPanicError),
 
     /// Cannot create a RateLimiterGroup
-    RateLimiterGroupCreate(rate_limiter::group::Error),
+    #[error("Cannot create a RateLimiterGroup: {0}")]
+    RateLimiterGroupCreate(#[source] rate_limiter::group::Error),
 
     /// Cannot start sigwinch listener
-    StartSigwinchListener(std::io::Error),
+    #[error("Cannot start sigwinch listener: {0}")]
+    StartSigwinchListener(#[source] std::io::Error),
 
     // Invalid console info
+    #[error("Invalid console info")]
     InvalidConsoleInfo,
 
     // Invalid console fd
+    #[error("Invalid console fd")]
     InvalidConsoleFd,
 
     /// Cannot lock images of all block devices.
-    DiskLockError(virtio_devices::block::Error),
+    #[error("Cannot lock images of all block devices: {0}")]
+    DiskLockError(#[source] virtio_devices::block::Error),
 }
 
 pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs
index 314c10d229..90dae67379 100644
--- a/vmm/src/memory_manager.rs
+++ b/vmm/src/memory_manager.rs
@@ -30,6 +30,7 @@ use libc::_SC_NPROCESSORS_ONLN;
 #[cfg(target_arch = "x86_64")]
 use libc::{MAP_NORESERVE, MAP_POPULATE, MAP_SHARED, PROT_READ, PROT_WRITE};
 use serde::{Deserialize, Serialize};
+use thiserror::Error;
 use tracer::trace_scoped;
 use virtio_devices::BlocksState;
 #[cfg(target_arch = "x86_64")]
@@ -202,145 +203,188 @@ pub struct MemoryManager {
     uefi_flash: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
 }
 
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum Error {
     /// Failed to create shared file.
-    SharedFileCreate(io::Error),
+    #[error("Failed to create shared file: {0}")]
+    SharedFileCreate(#[source] io::Error),
 
     /// Failed to set shared file length.
-    SharedFileSetLen(io::Error),
+    #[error("Failed to set shared file length: {0}")]
+    SharedFileSetLen(#[source] io::Error),
 
     /// Mmap backed guest memory error
-    GuestMemory(MmapError),
+    #[error("Mmap backed guest memory error: {0}")]
+    GuestMemory(#[source] MmapError),
 
     /// Failed to allocate a memory range.
+    #[error("Failed to allocate a memory range")]
     MemoryRangeAllocation,
 
     /// Error from region creation
-    GuestMemoryRegion(MmapRegionError),
+    #[error("Error from region creation: {0}")]
+    GuestMemoryRegion(#[source] MmapRegionError),
 
     /// No ACPI slot available
+    #[error("No ACPI slot available")]
     NoSlotAvailable,
 
     /// Not enough space in the hotplug RAM region
+    #[error("Not enough space in the hotplug RAM region")]
     InsufficientHotplugRam,
 
     /// The requested hotplug memory addition is not a valid size
+    #[error("The requested hotplug memory addition is not a valid size")]
     InvalidSize,
 
     /// Failed to create the user memory region.
-    CreateUserMemoryRegion(hypervisor::HypervisorVmError),
+    #[error("Failed to create the user memory region: {0}")]
+    CreateUserMemoryRegion(#[source] hypervisor::HypervisorVmError),
 
     /// Failed to remove the user memory region.
-    RemoveUserMemoryRegion(hypervisor::HypervisorVmError),
+    #[error("Failed to remove the user memory region: {0}")]
+    RemoveUserMemoryRegion(#[source] hypervisor::HypervisorVmError),
 
     /// Failed to EventFd.
-    EventFdFail(io::Error),
+    #[error("Failed to EventFd: {0}")]
+    EventFdFail(#[source] io::Error),
 
     /// Eventfd write error
-    EventfdError(io::Error),
+    #[error("Eventfd write error: {0}")]
+    EventfdError(#[source] io::Error),
 
     /// Failed to virtio-mem resize
-    VirtioMemResizeFail(virtio_devices::mem::Error),
+    #[error("Failed to virtio-mem resize: {0}")]
+    VirtioMemResizeFail(#[source] virtio_devices::mem::Error),
 
     /// Cannot restore VM
-    Restore(MigratableError),
+    #[error("Cannot restore VM: {0}")]
+    Restore(#[source] MigratableError),
 
     /// Cannot restore VM because source URL is missing
+    #[error("Cannot restore VM because source URL is missing")]
     RestoreMissingSourceUrl,
 
     /// Cannot create the system allocator
+    #[error("Cannot create the system allocator")]
     CreateSystemAllocator,
 
     /// Invalid SGX EPC section size
     #[cfg(target_arch = "x86_64")]
+    #[error("Invalid SGX EPC section size")]
     EpcSectionSizeInvalid,
 
     /// Failed allocating SGX EPC region
     #[cfg(target_arch = "x86_64")]
+    #[error("Failed allocating SGX EPC region")]
     SgxEpcRangeAllocation,
 
     /// Failed opening SGX virtual EPC device
     #[cfg(target_arch = "x86_64")]
-    SgxVirtEpcOpen(io::Error),
+    #[error("Failed opening SGX virtual EPC device: {0}")]
+    SgxVirtEpcOpen(#[source] io::Error),
 
     /// Failed setting the SGX virtual EPC section size
     #[cfg(target_arch = "x86_64")]
-    SgxVirtEpcFileSetLen(io::Error),
+    #[error("Failed setting the SGX virtual EPC section size: {0}")]
+    SgxVirtEpcFileSetLen(#[source] io::Error),
 
     /// Failed opening SGX provisioning device
     #[cfg(target_arch = "x86_64")]
-    SgxProvisionOpen(io::Error),
+    #[error("Failed opening SGX provisioning device: {0}")]
+    SgxProvisionOpen(#[source] io::Error),
 
     /// Failed enabling SGX provisioning
     #[cfg(target_arch = "x86_64")]
-    SgxEnableProvisioning(hypervisor::HypervisorVmError),
+    #[error("Failed enabling SGX provisioning: {0}")]
+    SgxEnableProvisioning(#[source] hypervisor::HypervisorVmError),
 
     /// Failed creating a new MmapRegion instance.
     #[cfg(target_arch = "x86_64")]
-    NewMmapRegion(vm_memory::mmap::MmapRegionError),
+    #[error("Failed creating a new MmapRegion instance: {0}")]
+    NewMmapRegion(#[source] vm_memory::mmap::MmapRegionError),
 
     /// No memory zones found.
+    #[error("No memory zones found")]
     MissingMemoryZones,
 
     /// Memory configuration is not valid.
+    #[error("Memory configuration is not valid")]
     InvalidMemoryParameters,
 
     /// Forbidden operation. Impossible to resize guest memory if it is
     /// backed by user defined memory regions.
+    #[error("Impossible to resize guest memory if it is backed by user defined memory regions")]
     InvalidResizeWithMemoryZones,
 
     /// It's invalid to try applying a NUMA policy to a memory zone that is
     /// memory mapped with MAP_SHARED.
+    #[error("Invalid to try applying a NUMA policy to a memory zone that is memory mapped with MAP_SHARED")]
     InvalidSharedMemoryZoneWithHostNuma,
 
     /// Failed applying NUMA memory policy.
-    ApplyNumaPolicy(io::Error),
+    #[error("Failed applying NUMA memory policy: {0}")]
+    ApplyNumaPolicy(#[source] io::Error),
 
     /// Memory zone identifier is not unique.
+    #[error("Memory zone identifier is not unique")]
     DuplicateZoneId,
 
     /// No virtio-mem resizing handler found.
+    #[error("No virtio-mem resizing handler found")]
     MissingVirtioMemHandler,
 
     /// Unknown memory zone.
+    #[error("Unknown memory zone")]
     UnknownMemoryZone,
 
     /// Invalid size for resizing. Can be anything except 0.
+    #[error("Invalid size for resizing. Can be anything except 0")]
     InvalidHotplugSize,
 
     /// Invalid hotplug method associated with memory zones resizing capability.
+    #[error("Invalid hotplug method associated with memory zones resizing capability")]
     InvalidHotplugMethodWithMemoryZones,
 
     /// Could not find specified memory zone identifier from hash map.
+    #[error("Could not find specified memory zone identifier from hash map")]
     MissingZoneIdentifier,
 
     /// Resizing the memory zone failed.
+    #[error("Resizing the memory zone failed")]
     ResizeZone,
 
     /// Guest address overflow
+    #[error("Guest address overflow")]
     GuestAddressOverFlow,
 
     /// Error opening snapshot file
-    SnapshotOpen(io::Error),
+    #[error("Error opening snapshot file: {0}")]
+    SnapshotOpen(#[source] io::Error),
 
     // Error copying snapshot into region
-    SnapshotCopy(GuestMemoryError),
+    #[error("Error copying snapshot into region: {0}")]
+    SnapshotCopy(#[source] GuestMemoryError),
 
     /// Failed to allocate MMIO address
+    #[error("Failed to allocate MMIO address")]
     AllocateMmioAddress,
 
     #[cfg(target_arch = "aarch64")]
     /// Failed to create UEFI flash
-    CreateUefiFlash(HypervisorVmError),
+    #[error("Failed to create UEFI flash: {0}")]
+    CreateUefiFlash(#[source] HypervisorVmError),
 
     /// Using a directory as a backing file for memory is not supported
+    #[error("Using a directory as a backing file for memory is not supported")]
     DirectoryAsBackingFileForMemory,
 
     /// Failed to stat filesystem
-    GetFileSystemBlockSize(io::Error),
+    #[error("Failed to stat filesystem: {0}")]
+    GetFileSystemBlockSize(#[source] io::Error),
 
     /// Memory size is misaligned with default page size or its hugepage size
+    #[error("Memory size is misaligned with default page size or its hugepage size")]
     MisalignedMemorySize,
 }
 


Reviews:
user: login: rbradford
body: Thanks for tackling this - this is a biggie!
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T14:29:05Z
user: login: phip1611
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T14:49:55Z
user: login: rbradford
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T19:48:37Z
user: login: phip1611
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T07:27:24Z
user: login: rbradford
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-16T08:08:28Z

Review comments:
diff_hunk: @@ -23,21 +24,28 @@ const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
 const NUM_DEVICE_IDS: usize = 32;
 
 /// Errors for device manager.
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum PciRootError {
     /// Could not allocate device address space for the device.
+    #[error("Could not allocate device address space for the device")]
path: pci/src/bus.rs
user: login: rbradford
body: I think the convention is that we put the embedded error after the message with a colon separating them - like `"Could not allocate device address space for the device: {0}"`
```
rockhopper:~/src/cloud-hypervisor (main)$ git grep "#\[error.*: {0}" | wc -l
586
```
created_at: 2025-05-15T14:28:49Z
author_association: MEMBER
diff_hunk: @@ -23,21 +24,28 @@ const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
 const NUM_DEVICE_IDS: usize = 32;
 
 /// Errors for device manager.
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum PciRootError {
     /// Could not allocate device address space for the device.
+    #[error("Could not allocate device address space for the device")]
path: pci/src/bus.rs
user: login: phip1611
body: Please note that I'd like to change that treewide in/for #7066

created_at: 2025-05-15T14:49:54Z
author_association: MEMBER
diff_hunk: @@ -23,21 +24,28 @@ const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
 const NUM_DEVICE_IDS: usize = 32;
 
 /// Errors for device manager.
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum PciRootError {
     /// Could not allocate device address space for the device.
+    #[error("Could not allocate device address space for the device")]
path: pci/src/bus.rs
user: login: rbradford
body: In which case we don't need to add that here.
created_at: 2025-05-15T19:48:37Z
author_association: MEMBER
diff_hunk: @@ -23,21 +24,28 @@ const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
 const NUM_DEVICE_IDS: usize = 32;
 
 /// Errors for device manager.
-#[derive(Debug)]
+#[derive(Error, Debug)]
 pub enum PciRootError {
     /// Could not allocate device address space for the device.
+    #[error("Could not allocate device address space for the device")]
path: pci/src/bus.rs
user: login: phip1611
body: So for this commit, I follow the `": {0}"` convention for the inner error for all enum variants that I touch anyway. This is likely going to be removed again in #7066, but this is another story
created_at: 2025-05-16T07:27:23Z
author_association: MEMBER

PR comments:
user: login: phip1611
created_at: 2025-05-13T14:48:20Z
body: I was quite careful to ensure to not have any copy&paste errors. Fingers crossed!
author_association: MEMBER
user: login: rbradford
created_at: 2025-05-15T19:50:21Z
body: @phip1611  Do you think we should hold off on this until #7066 gets a resolution to land since I think we might lose some detail if we land this and then that doesn't land?
author_association: MEMBER
user: login: phip1611
created_at: 2025-05-16T08:33:47Z
body: > @phip1611 Do you think we should hold off on this until https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7066 gets a resolution to land since I think we might lose some detail if we lan

Yes, I agree. I adapted this PR to follow the current style
author_association: MEMBER
user: login: rbradford
created_at: 2025-05-16T09:40:20Z
body: @phip1611 I'm confused - you adapted it to to the older style which means we can merge this sooner rather than holding it off?
author_association: MEMBER
user: login: phip1611
created_at: 2025-05-16T09:56:22Z
body: Sorry for the confusion. 

> @phip1611 I'm confused - you adapted it to to the older style which means we can merge this sooner rather than holding it off?

Yes, adapted to the old style where each error's Display::fmt() also prints the sub error. We now have proper `std::error::Error` for `DisplayManagerError` and all referenced sub errors, which is a major improvement, giving future work more flexiblity. IMHO merging this is an improvement. It does not hinder #7066 in any way
author_association: MEMBER