AprilNEA/OpenLogi · error

no online HID++ device found — is a Logi device paired and…

Error message

no online HID++ device found — is a Logi device paired and awake?

What it means

Built by `no_match_err` in the diagnostic command when the enumerated candidate list is completely empty, meaning no HID++ device was online at selection time. The generic wording (with the paired/awake hint) is deliberately used instead of naming a query, because there is nothing to match against. The caller tests `devices.is_empty()` first, so this branch always means zero candidates.

Solutions

  1. Plug in the Bolt/Unifying receiver or reconnect the device via Bluetooth, and wake it (move the mouse / press a key).
  2. Verify enumeration sees anything at all: run `openlogi list` (it falls back to direct enumeration when no agent is running).
  3. On macOS, confirm Input Monitoring/Accessibility permissions are granted so the HID devices can be opened.
  4. If the device is paired but dormant, press its reset/connect button to wake the radio, then retry.

Example fix

// before: running diagnostics with nothing connected
$ openlogi diag dpi
// error: no online HID++ device found — is a Logi device paired and awake?
// after: connect and verify first
$ openlogi list   # confirms the device is enumerated
$ openlogi diag dpi
Defensive patterns

Strategy: fallback

Validate before calling

// check enumeration before running diagnostics
let devices = enumerate_candidates()?;
if devices.is_empty() {
    eprintln!("no HID++ device online — connect/wake the device first");
    std::process::exit(1);
}

Try / catch

match select_device(&devices, query) {
    Ok(dev) => run_diag(dev),
    Err(e) if is_no_device_error(&e) => {
        eprintln!("waiting for device...");
        wait_for_device(Duration::from_secs(10))?;
        retry_once()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Running any `openlogi` diagnostic subcommand that calls `select_device`/`no_match_err` when device enumeration returns no online candidates — no receiver with a paired device, no Bluetooth-direct device awake, or no wired device present.

Common situations: Logitech device powered off or in sleep; receiver not plugged in; Bluetooth mouse/keyboard not connected to the host; device awake but not yet enumerated because it is still initializing after a reconnect.

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 AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13). Data as JSON: /api/errors/a026be46e157b958. Report an issue: GitHub.

Appendix: source

Thrown at crates/openlogi-cli/src/cmd/diag.rs:85

            let route =
                DeviceRoute::device_route_for(&inv, paired.slot).unwrap_or(DeviceRoute::Direct {
                    vendor_id: inv.receiver.vendor_id,
                    product_id: inv.receiver.product_id,
                });
            let name = paired
                .codename
                .clone()
                .unwrap_or_else(|| format!("Slot {}", paired.slot));
            out.push(Candidate { route, name });
        }
    }
    Ok(out)
}

/// Build a helpful "couldn't pick a device" error that lists what *is* online.
fn no_match_err(devices: &[Candidate], query: Option<&str>) -> anyhow::Error {
    if devices.is_empty() {
        return anyhow!("no online HID++ device found — is a Logi device paired and awake?");
    }
    let list = devices
        .iter()
        .map(|c| format!("    - {} ({})", c.name, c.route))
        .collect::<Vec<_>>()
        .join("\n");
    match query {
        Some(q) => anyhow!("no online device matches `--device {q}`.\n  online devices:\n{list}"),
        None => anyhow!(
            "could not pick a device automatically.\n  online devices:\n{list}\n  \
             pass --device <name> to choose one."
        ),
    }
}

/// Pick the device a diag should run against.
///
/// Selection order:

View on GitHub (pinned to e846e6f4b4)