ClementTsang/bottom · error · anyhow::Error

IORegistryEntryCreateCFProperties failed, error code

Error message

IORegistryEntryCreateCFProperties failed, error code {result}.

What it means

The properties helper calls IORegistryEntryCreateCFProperties to read all registry properties of an IOKit entry into a CFMutableDictionary. If the kernel call returns a non-KERN_SUCCESS result, this error reports the kern_return_t code.

Solutions

  1. Re-enumerate the IOKit entries rather than reusing stale io_object handles
  2. Check the returned error code (e.g. kIOReturnBadArgument implies an invalid entry)
  3. Retry disk stats collection; transient failures often resolve on the next sweep
  4. Guard device-removal races by tolerating per-device failures during iteration

Example fix

// before
let props = entry.properties()?;
// after
let props = match entry.properties() {
    Ok(p) => p,
    Err(e) => { log::debug!("device vanished, skipping: {e}"); continue; },
};
Defensive patterns

Strategy: try-catch

Try / catch

match entry.properties() {
    Ok(p) => process(p),
    Err(e) if e.to_string().contains("IORegistryEntryCreateCFProperties") => {
        log::debug!("device entry vanished: {e}"); // skip device
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling properties() (used while walking the IOKit disk/IO hierarchy in io_stats) on an io_object whose registry entry is invalid, already destroyed, or lacks a connection to the registry.

Common situations: Enumerating disks while devices are hot-unplugged mid-iteration, or querying entries obtained from a failed/partial IOKit traversal.

Related errors


AI-assisted analysis of ClementTsang/bottom@b77d317502 (2026-09-07). Data as JSON: /api/errors/601a421d3d716c19. Report an issue: GitHub.

Appendix: source

Thrown at src/collection/disks/unix/macos/io_kit/io_object.rs:41

impl IoObject {
    /// Returns a typed dictionary with this object's properties.
    pub fn properties(&self) -> anyhow::Result<CFDictionary<CFString, CFType>> {
        // SAFETY: The IOKit call should be fine, the arguments are safe. The
        // `assume_init` should also be fine, as we guard against it with a
        // check against `result` to ensure it succeeded.
        unsafe {
            let mut props = mem::MaybeUninit::<CFMutableDictionaryRef>::uninit();

            let result = IORegistryEntryCreateCFProperties(
                self.0,
                props.as_mut_ptr(),
                kCFAllocatorDefault,
                0,
            );

            if result != kern_return::KERN_SUCCESS {
                bail!("IORegistryEntryCreateCFProperties failed, error code {result}.")
            } else {
                let props = props.assume_init();
                Ok(CFMutableDictionary::wrap_under_create_rule(props).to_immutable())
            }
        }
    }

    /// Gets the [`kIOServicePlane`] parent [`io_object_t`] for this
    /// [`io_object_t`], if there is one.
    pub fn service_parent(&self) -> anyhow::Result<IoObject> {
        let mut parent: io_registry_entry_t = 0;

        // SAFETY: IOKit call, the arguments should be safe.
        let result = unsafe {
            IORegistryEntryGetParentEntry(self.0, kIOServicePlane.as_ptr().cast(), &mut parent)
        };

        if result != kern_return::KERN_SUCCESS {

View on GitHub (pinned to b77d317502)