ClementTsang/bottom · warning

missing key

Error message

missing key

What it means

macOS I/O Kit helper `get_dict(dict, raw_key)` looks up `raw_key` in a `CFDictionary` of an IOService/IORegistryEntry and bails with 'missing key' when the key is absent or the value cannot be wrapped as a CFDictionary. Called from `get_device_io`, it means the expected IORegistry dictionary entry (e.g. statistics/protocol characteristics) does not exist for this device.

Solutions

  1. Treat missing keys as optional data — skip the device or default the value rather than failing the whole collection
  2. Verify the key string matches the exact IORegistry key name (case-sensitive) for your macOS version
  3. Check the device in IORegistryExplorer to confirm which keys it actually publishes
  4. Filter device classes (only physical/internal disks) before querying IOStatistics

Example fix

// before
let dict = io_object::get_dict(&dict, "kIOPropertyNVMeSMARTData")?;
// after
let smart = match io_object::get_dict(&dict, "kIOPropertyNVMeSMARTData") {
    Ok(d) => d,
    Err(_) => {
        // device does not expose this key; continue with defaults
        Default::default()
    },
};
Defensive patterns

Strategy: fallback

Validate before calling

// Confirm the key exists before requesting a dictionary value
let key = core_foundation::string::CFString::new("target_key");
if dict.find(key).is_some() {
    let d = io_object::get_dict(&dict, "target_key")?;
} else {
    // device does not publish this key; use defaults
}

Type guard

fn optional_dict(dict: &CFDictionary<CFString, CFType>, key: &str)
    -> Option<CFDictionary<CFString, CFType>> {
    io_object::get_dict(dict, key).ok()
}

Try / catch

let io_dict = match io_object::get_dict(&entry_dict, "IOStatistics") {
    Ok(d) => Some(d),
    Err(e) if e.to_string() == "missing key" => None,
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: `get_device_io` querying a disk whose IORegistry entry lacks the expected dictionary key; the value under the key exists but is not a CFDictionary; device hardware/firmware does not publish the expected IORegistry data; virtual or external drives missing the key.

Common situations: Running on Macs with virtualized disks (AVFarming, VMs) or USB bridges that do not expose IORegistry statistics; macOS version differences in IORegistry layout; requesting keys from non-physical devices.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

) -> anyhow::Result<CFDictionary<CFString, CFType>> {
    let key = CFString::from_static_string(raw_key);

    dict.find(&key)
        .map(|value_ref| {
            // SAFETY: Only used for debug asserts, system API call that should
            // be safe.
            unsafe {
                debug_assert!(value_ref.type_of() == CFDictionaryGetTypeID());
            }

            // "Casting" `CFDictionary<*const void, *const void>` into a needed
            // dict type
            let ptr = value_ref.to_void() as CFDictionaryRef;

            // SAFETY: System API call, it should be safe?
            unsafe { CFDictionary::wrap_under_get_rule(ptr) }
        })
        .ok_or_else(|| anyhow!("missing key"))
}

pub fn get_i64(
    dict: &CFDictionary<CFString, CFType>, raw_key: &'static str,
) -> anyhow::Result<i64> {
    let key = CFString::from_static_string(raw_key);

    dict.find(&key)
        .and_then(|value_ref| {
            // SAFETY: Only used for debug asserts, system API call that should
            // be safe.
            unsafe {
                debug_assert!(value_ref.type_of() == CFNumberGetTypeID());
            }
            value_ref.downcast::<CFNumber>()
        })
        .and_then(|number| number.to_i64())
        .ok_or_else(|| anyhow!("missing key"))

View on GitHub (pinned to b77d317502)