Kuberwastaken/claurst · error · anyhow::Error

No API key found for voice transcription. Set…

Error message

No API key found for voice transcription. Set OPENAI_API_KEY, or point WHISPER_ENDPOINT_URL to a local Whisper server (e.g. whisper.cpp or faster-whisper).

What it means

record_and_transcribe needs credentials to call the transcription endpoint: it looks for an API key and, when absent, emits VoiceEvent::Error and fails. The message points to the two supported paths: an OPENAI_API_KEY or a local WHISPER_ENDPOINT_URL server. This is an explicit configuration prerequisite, not a runtime failure.

Solutions

  1. Export OPENAI_API_KEY with a valid key.
  2. Set WHISPER_ENDPOINT_URL to a local Whisper server (whisper.cpp / faster-whisper) that needs no key.
  3. Check the current transcript path: read the key lookup in voice.rs to confirm which env vars it probes and their exact spelling.

Example fix

// before
$ cargo run -- --voice
// after
$ export OPENAI_API_KEY=sk-...   # or WHISPER_ENDPOINT_URL=http://localhost:8080
$ cargo run -- --voice
Defensive patterns

Strategy: validation

Validate before calling

fn voice_configured() -> bool {
    std::env::var("OPENAI_API_KEY").is_ok()
        || std::env::var("WHISPER_ENDPOINT_URL").is_ok()
}

Prevention

When it happens

Trigger: Recording + transcribing without OPENAI_API_KEY set and without WHISPER_ENDPOINT_URL pointing at a local Whisper server.

Common situations: Fresh install with no env vars; CI/docker where env vars aren't passed through; user intended to use a local whisper.cpp server but the endpoint env var is unset or misspelled.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/7d446ccbd562e17f. Report an issue: GitHub.

Appendix: source

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

        }

        // Resolve API key: explicit config first, then OPENAI_API_KEY, then ANTHROPIC_API_KEY.
        let api_key_opt = config
            .api_key
            .as_deref()
            .filter(|k| !k.is_empty())
            .map(|k| k.to_string())
            .or_else(|| std::env::var("OPENAI_API_KEY").ok().filter(|k| !k.is_empty()))
            .or_else(|| std::env::var("ANTHROPIC_API_KEY").ok().filter(|k| !k.is_empty()));

        let api_key = match api_key_opt {
            Some(k) => k,
            None => {
                let msg = "No API key found for voice transcription. \
                           Set OPENAI_API_KEY, or point WHISPER_ENDPOINT_URL to a \
                           local Whisper server (e.g. whisper.cpp or faster-whisper).".to_string();
                let _ = event_tx.send(VoiceEvent::Error(msg.clone())).await;
                return Err(anyhow::anyhow!(msg));
            }
        };

        match transcribe_audio(
            &samples,
            sample_rate,
            &api_key,
            config.language.as_deref(),
            &config.model,
            config.endpoint_url.as_deref(),
        )
        .await
        {
            Ok(text) => {
                let _ = event_tx.send(VoiceEvent::TranscriptReady(text)).await;
            }
            Err(e) => {
                let _ = event_tx

View on GitHub (pinned to b0637c97ec)