AprilNEA/OpenLogi · error
failed to enumerate HID++ devices for direct fixture capture
Error message
failed to enumerate HID++ devices for direct fixture capture
What it means
`prepare_contribution_target` enumerates HID++ devices directly via `openlogi_hid::enumerate()` to pick a capture target for direct fixture capture. Any enumeration failure is collapsed into this error because capture cannot proceed without a device list; no candidates can be built.
Solutions
- Fix the underlying enumeration failure (check `openlogi list` for a more detailed error)
- On Linux: add udev rules or run with sufficient privileges for hidraw access
- On macOS: grant Input Monitoring permission to the terminal/binary, per docs/DEVELOPMENT.md
- Stop the running agent if it holds devices exclusively, or use the agent-backed capture path instead of direct capture
- Confirm a device is actually connected and is an HID++ device
Example fix
// before (Linux, permission denied on hidraw) openlogi fixture record-case ... // after sudo cp packaging/99-openlogi.rules /etc/udev/rules.d/ && sudo udevadm control --reload && sudo udevadm trigger openlogi fixture record-case ...
Defensive patterns
Strategy: fallback
Validate before calling
// check direct HID access before starting capture
match openlogi_hid::enumerate().await {
Ok(inv) if !inv.is_empty() => println!("{} HID++ device(s) reachable", inv.len()),
Ok(_) => eprintln!("no HID++ devices visible; connect a device"),
Err(e) => eprintln!("enumeration unavailable: {e}; fix permissions or use agent-backed capture"),
} Try / catch
match prepare_contribution_target(...).await {
Ok(target) => capture(target),
Err(e) if e.to_string().contains("failed to enumerate") =>
eprintln!("{e:#}; grant hidraw/Input Monitoring access or use the agent path"),
Err(e) => return Err(e),
} Prevention
- Install udev rules / run with adequate privileges on Linux before hardware commands
- Grant Input Monitoring to the CLI's host app on macOS once, per docs
- Stop the agent (or use agent-backed capture) to avoid exclusive device contention
- Verify with `openlogi list` that devices enumerate before long capture sessions
When it happens
Trigger: `openlogi_hid::enumerate()` returns `Err` before target selection — typically the backend cannot open/claim HID device files, or the OS denies access (Linux: no permission on `/dev/hidraw*`; macOS: missing Input Monitoring permission for the CLI).
Common situations: Running the record command without `sudo`/udev rules on Linux, running the macOS binary from a terminal without Input Monitoring granted, another process (the agent) holding the device exclusively, or no HID transport backend available.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- raw-HID devices support profile-only contributions
- the selected device has no stable synthetic identity for…
- the selected direct-capture target does not match the…
- --name must not be empty
- --channel must not be empty
AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13).
Data as JSON: /api/errors/e8e96448750ef09f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/openlogi-cli/src/cmd/fixture/record_case.rs:273
cassette before committing it."
);
Ok(())
}
pub(super) async fn prepare_contribution_target(selector: Option<&str>) -> Result<CaptureTarget> {
let agent_guard = acquire_capture_ownership().await?;
eprintln!(
"warning: fixture case capture reads hardware directly with this CLI process's own HID \
permission and identity, not the OpenLogi agent"
);
eprintln!(
"warning: discovery may enable wireless notifications and request arrival reports on \
connected receivers before target selection; notification flags are not restored. \
Captured operations do not change device settings or pairings."
);
let inventories = openlogi_hid::enumerate()
.await
.map_err(|_| anyhow!("failed to enumerate HID++ devices for direct fixture capture"))?;
let candidates = online_targets(&inventories);
let target = target_selection::select_target(&candidates, selector)?;
Ok(CaptureTarget {
target,
_agent_guard: agent_guard,
})
}
pub(super) async fn capture_for_contribution(
operation: FixtureOperation,
target: &CaptureTarget,
name: &str,
channel: &str,
capacity: usize,
identity_plan: &HidCassetteIdentityPlan,
) -> Result<HidCassette> {
let (recording, observation) = capture(operation, target.route(), capacity).await?;
let candidates = audit::sanitize_recording_with_plan(recording, name, channel, identity_plan)?;View on GitHub (pinned to e846e6f4b4)