AprilNEA/OpenLogi · error

no Logitech camera found

Error message

no Logitech camera found

What it means

`snapshot run` needs a camera unique id: if `--camera` is not given it takes the first camera from `openlogi_camera::enumerate_cameras()`. When enumeration returns an empty list, the `ok_or_else` turns the `None` into this anyhow error. It means no Logitech UVC camera was visible to the camera layer at all.

Solutions

  1. Plug in the Logitech camera (or confirm it is a Logitech model, not another vendor).
  2. Pass the explicit device with `--camera <unique-id>` after confirming its id via enumeration.
  3. Close apps holding the camera exclusively, then retry.
  4. On macOS, grant Camera permission to the process in System Settings → Privacy & Security → Camera.
  5. Replug the camera / try another USB port to rule out enumeration flakiness.

Example fix

// before
$ openlogi snapshot out.png
error: no Logitech camera found

// after — plug the camera in, or target it explicitly once its id is known
$ openlogi snapshot out.png --camera "usb:046d:085e"
Defensive patterns

Strategy: fallback

Validate before calling

let cameras = openlogi_camera::enumerate_cameras();
if cameras.is_empty() {
    eprintln!("no Logitech camera visible; check connection/permissions");
    return Ok(());
}

Try / catch

// snapshot::run returns anyhow::Result; intercept the enumeration failure
match snapshot_run(args) {
    Err(e) if e.to_string().contains("no Logitech camera found") => {
        eprintln!("connect a Logitech camera or pass --camera <unique-id>");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running the `snapshot` command without `--camera` while `enumerate_cameras()` returns zero Logitech cameras (the iterator's `.next()` is `None`).

Common situations: No camera plugged in or it is a non-Logitech webcam; the camera is claimed exclusively by another app (Zoom/Teams) or the OS; on macOS the Camera (TCC) permission was denied so enumeration is empty; a USB hub/dock dropped the device.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13). Data as JSON: /api/errors/f45c06aaff7cc018. Report an issue: GitHub.

Appendix: source

Thrown at crates/openlogi-cli/src/cmd/snapshot.rs:30

#[derive(Debug, Args)]
pub struct SnapshotArgs {
    /// Output PNG path.
    #[arg(default_value = "snapshot.png")]
    pub path: String,
    /// Capture from the camera with this unique id (default: first Logitech).
    #[arg(long)]
    pub camera: Option<String>,
}

pub fn run(args: SnapshotArgs) -> Result<()> {
    let unique_id = match args.camera {
        Some(id) => id,
        None => openlogi_camera::enumerate_cameras()
            .into_iter()
            .next()
            .map(|camera| camera.unique_id)
            .ok_or_else(|| anyhow!("no Logitech camera found"))?,
    };

    println!("capturing one frame from {unique_id} …");
    let frame = openlogi_camera::capture_frame(&unique_id, Duration::from_secs(5))
        .map_err(|e| anyhow!("{e}"))?;
    // Frames are stored BGRA (gpui's order); PNG wants RGBA, so swap R/B once.
    let mut rgba = frame.bgra;
    for px in rgba.as_chunks_mut::<4>().0 {
        px.swap(0, 2);
    }
    write_png(&args.path, frame.width, frame.height, &rgba)
        .with_context(|| format!("writing {}", args.path))?;
    println!("wrote {}x{} → {}", frame.width, frame.height, args.path);
    Ok(())
}

fn write_png(path: &str, width: u32, height: u32, rgba: &[u8]) -> Result<()> {
    let file = std::fs::File::create(path)?;

View on GitHub (pinned to e846e6f4b4)