{"record":{"id":"332dc37fcbbede3d","repo":"cjpais/Handy","slug":"failed-to-create-audiorecorder","errorCode":null,"errorMessage":"Failed to create AudioRecorder: {}","messagePattern":"Failed to create AudioRecorder: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"src-tauri/src/managers/audio.rs","lineNumber":331,"sourceCode":"        frames_for_duration_ms(VAD_STREAMING_HANGOVER_MS, frame_samples);\n    let onset_frames = frames_for_duration_ms(VAD_ONSET_MS, frame_samples);\n    let smoothed_vad = SmoothedVad::new(\n        detector,\n        prefill_frames,\n        offline_hangover_frames,\n        onset_frames,\n    );\n\n    info!(\n        \"Initialized {:?} VAD backend ({} samples/frame)\",\n        backend, frame_samples\n    );\n\n    // Recorder with VAD, a spectrum-level callback that forwards level updates to\n    // the frontend, and an audio-frame callback that feeds live streaming via a\n    // shared `StreamRouter` (captured directly, not via Tauri state — see its docs).\n    let recorder = AudioRecorder::new()\n        .map_err(|e| anyhow::anyhow!(\"Failed to create AudioRecorder: {}\", e))?\n        .with_vad(\n            Box::new(smoothed_vad),\n            offline_hangover_frames,\n            streaming_hangover_frames,\n        )\n        .with_selected_channel(selected_channel)\n        .with_level_callback({\n            let app_handle = app_handle.clone();\n            move |levels| {\n                utils::emit_levels(&app_handle, &levels);\n            }\n        })\n        .with_audio_callback({\n            let router = stream_router;\n            move |frame| {\n                router.feed(frame);\n            }\n        });","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/cjpais/Handy/blob/c6fa60da2f13a5af660fba17f37af548855119c5/src-tauri/src/managers/audio.rs#L313-L349","documentation":"AudioRecorder::new() failed at recorder construction — acquiring the default audio input device and host via cpal. This throws when the machine exposes no default input device, the device is exclusively held by another process, or the OS denies microphone access (macOS TCC). It is the first audio-touching call in create_audio_recorder, so it fails before any VAD/streaming setup.","triggerScenarios":"No microphone connected or enabled; mic exclusively captured by another app; macOS microphone permission not granted to the app; headless/CI environment with no audio devices; default device switched/disconnected between enumeration and recorder creation.","commonSituations":"Fresh macOS install prompting for mic permission and user denying; Bluetooth headset disconnecting mid-session; remote desktop / VM sessions without audio passthrough; another app (e.g. DAW or meeting software with exclusive mode) holding the device.","solutions":["Connect or re-enable a microphone and retry","On macOS: System Settings → Privacy & Security → Microphone → allow the app","Close apps that may hold the device exclusively, or switch them to shared mode","Select a specific input device in Handy settings rather than relying on the default","On macOS restart coreaudiod; on Linux check PipeWire/Pulse is running and the source is not suspended"],"exampleFix":"// before\nlet recorder = AudioRecorder::new()\n    .map_err(|e| anyhow::anyhow!(\"Failed to create AudioRecorder: {}\", e))?\n\n// after — preflight the device so users get a precise message instead of a generic init error\nlet host = cpal::default_host();\nlet device = host.default_input_device().ok_or_else(|| {\n    anyhow::anyhow!(\"No default microphone found — connect an input device or grant microphone permission\")\n})?;\nlet recorder = AudioRecorder::new()\n    .map_err(|e| anyhow::anyhow!(\"Failed to create AudioRecorder: {}\", e))?","handlingStrategy":"fallback","validationCode":"// preflight the default input device before constructing the recorder\nlet host = cpal::default_host();\nif host.default_input_device().is_none() {\n    anyhow::bail!(\n        \"No microphone available — connect an input device or grant microphone permission\"\n    );\n}","typeGuard":null,"tryCatchPattern":"match create_audio_recorder(&vad_path, ...) {\n    Err(e) if e.to_string().contains(\"Failed to create AudioRecorder\") => {\n        // device problem, not code: enumerate devices, tell the user to connect/grant,\n        // and fall back to a device-picker instead of auto-retrying the default\n    }\n    other => other?,\n}","preventionTips":["Enumerate input devices and let users pick an explicit device instead of relying on the default","Handle device-disconnect events: rebuild the recorder on device-change rather than crashing the session","On first run, guide users through macOS microphone permission before recording starts"],"tags":["rust","audio","cpal","microphone","device-init","permissions"],"backgroundTag":"audio-device-init-failed","analyzedSha":"c6fa60da2f13a5af660fba17f37af548855119c5","analyzedAt":"2026-08-28T14:36:54.174Z","contentChangedAt":"2026-08-28T14:36:54.174Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}