Kuberwastaken/claurst · error · anyhow::Error

No input device available

Error message

No input device available

What it means

record_audio asks cpal's default host for the default input device; when none exists it returns this error before any stream setup. The library cannot capture audio without a device, so it fails immediately with a clear message.

Solutions

  1. Connect or enable a microphone/input device.
  2. Start the system audio server (pipewire/pulseaudio) on Linux.
  3. Check availability() or enumerate input devices before attempting recording and show a friendly message.
  4. On Linux, install ALSA/PipeWire dev runtime libs so cpal's host can find devices.

Example fix

// before
let text = voice.record_and_transcribe().await?;
// after
if cpal::default_host().default_input_device().is_none() {
    eprintln!("no microphone detected; voice input disabled");
    return Ok(());
}
let text = voice.record_and_transcribe().await?;
Defensive patterns

Strategy: fallback

Validate before calling

fn has_input_device() -> bool {
    cpal::default_host().default_input_device().is_some()
}

Try / catch

match voice.record_and_transcribe().await {
    Ok(t) => t,
    Err(e) if e.to_string().contains("No input device") => {
        eprintln!("no microphone; falling back to typed input");
        typed_input()?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: record_audio running on a machine where cpal::default_host().default_input_device() returns None — no microphone, no audio subsystem, or audio daemon not running.

Common situations: Headless servers/containers with no sound hardware; SSH sessions without PulseAudio/PipeWire; VM with no audio passthrough; microphone disabled at BIOS/OS level; PulseAudio not started.

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 Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/74ed127a48a5f2f4. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/core/src/voice.rs:396

    }
}

// ---------------------------------------------------------------------------
// Audio capture (cpal, feature-gated)
// ---------------------------------------------------------------------------

#[cfg(feature = "voice")]
async fn record_audio(
    is_recording: Arc<AtomicBool>,
    event_tx: mpsc::Sender<VoiceEvent>,
) -> anyhow::Result<(Vec<f32>, u32)> {
    use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
    use std::time::Duration;

    let host = cpal::default_host();
    let device = host
        .default_input_device()
        .ok_or_else(|| anyhow::anyhow!("No input device available"))?;

    let supported_config = device.default_input_config()?;
    let sample_rate = supported_config.sample_rate().0;
    let channels = supported_config.channels() as usize;

    let samples: Arc<Mutex<Vec<f32>>> = Arc::new(Mutex::new(Vec::new()));
    let samples_clone = samples.clone();

    let err_tx = event_tx.clone();
    let is_recording_for_err = is_recording.clone();
    let stream = {
        let config: cpal::StreamConfig = supported_config.into();
        device.build_input_stream(
            &config,
            move |data: &[f32], _: &cpal::InputCallbackInfo| {
                // Mix down to mono if needed
                let mut s = samples_clone.lock().unwrap();
                if channels == 1 {

View on GitHub (pinned to b0637c97ec)