{"record":{"id":"de956f5b4289172c","repo":"zeroclaw-labs/zeroclaw","slug":"transcription-is-enabled-but-no-transcription-prov-de956f","errorCode":null,"errorMessage":"Transcription is enabled but no transcription provider registered successfully. Configure at least one of: [providers.transcription.<type>.<alias>], [transcription] (Groq) with api_key + api_url, [transcription.openai], [transcription.deepgram], [transcription.assemblyai], [transcription.google], or [transcription.local_whisper].","messagePattern":"Transcription is enabled but no transcription provider registered successfully\\. Configure at least one of: \\[providers\\.transcription\\.<type>\\.<alias>\\], \\[transcription\\] \\(Groq\\) with api_key \\+ api_url, \\[transcription\\.openai\\], \\[transcription\\.deepgram\\], \\[transcription\\.assemblyai\\], \\[transcription\\.google\\], or \\[transcription\\.local_whisper\\]\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/transcription.rs","lineNumber":979,"sourceCode":"        })\n    }\n\n    pub fn from_config_for_agent(config: &Config, agent_alias: Option<&str>) -> Result<Self> {\n        if matches!(config.transcription.max_audio_bytes, Some(0)) {\n            bail!(\"transcription.max_audio_bytes must be greater than zero\");\n        }\n\n        let mut transcription_providers: HashMap<String, Box<dyn TranscriptionProvider>> =\n            HashMap::new();\n\n        Self::register_legacy_providers(&mut transcription_providers, &config.transcription);\n        Self::register_typed_providers(\n            &mut transcription_providers,\n            &config.providers.transcription,\n        );\n\n        if config.transcription.enabled && transcription_providers.is_empty() {\n            bail!(\n                \"Transcription is enabled but no transcription provider registered \\\n                 successfully. Configure at least one of: [providers.transcription.<type>.<alias>], \\\n                 [transcription] (Groq) with api_key + api_url, [transcription.openai], \\\n                 [transcription.deepgram], [transcription.assemblyai], [transcription.google], \\\n                 or [transcription.local_whisper].\"\n            );\n        }\n\n        let agent_transcription_provider = agent_alias\n            .or_else(|| config.resolved_runtime_agent_alias())\n            .and_then(|alias| config.agents.get(alias))\n            .map(|a| a.transcription_provider.as_str().to_string())\n            .unwrap_or_default();\n\n        Ok(Self {\n            transcription_providers,\n            max_audio_bytes: config.transcription.max_audio_bytes,\n            agent_transcription_provider,","sourceCodeStart":961,"sourceCodeEnd":997,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/transcription.rs#L961-L997","documentation":"from_config_for_agent() bails when transcription is enabled and neither the legacy [transcription.*] blocks nor the typed [providers.transcription.<type>.<alias>] entries produced a single registered provider. Unlike new() (error 295), this constructor registers both families, so hitting this error means both sources were absent or invalid — invalid typed entries are skipped with the WARN 'typed transcription provider skipped (config error)' naming the config path.","triggerScenarios":"transcription.enabled = true with no usable provider anywhere: legacy blocks missing their api_key/api_url, typed entries failing from_typed_config (bad values), or both absent. Each failed registration logs a WARN with the config path before the final empty-map bail.","commonSituations":"Renamed or misspelled provider block (e.g. [transcription.open_ai]); typed entry with an invalid field value skipped at startup and never noticed until the first voice note; secrets file not merged so all api_keys are empty strings.","solutions":["Add one complete provider config — legacy ([transcription] Groq api_key+api_url, [transcription.openai], ...) or typed ([providers.transcription.groq.main])","Check the startup WARN logs for 'typed transcription provider skipped (config error)' — the config_path attr names the exact broken entry","Verify api_key values are actually populated after secrets merging","Set transcription.enabled = false if transcription is not intended"],"exampleFix":"# before\n[transcription]\nenabled = true\n# no provider anywhere -> error\n\n# after (typed provider)\n[providers.transcription.openai.main]\napi_key = \"sk-...\"\napi_url = \"https://api.openai.com/v1/audio/transcriptions\"","handlingStrategy":"validation","validationCode":"fn transcription_startup_ok(cfg: &Config) -> bool {\n    !cfg.transcription.enabled || provider_config_present(cfg)\n}\n\nfn provider_config_present(cfg: &Config) -> bool {\n    let t = &cfg.transcription;\n    t.api_key.as_deref().is_some_and(|k| !k.is_empty())\n        || t.openai.is_some() || t.deepgram.is_some() || t.assemblyai.is_some()\n        || t.google.is_some() || t.local_whisper.is_some()\n        || cfg.providers.transcription.iter_entries().next().is_some()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate config before deploy: enabled transcription must have at least one complete provider block","Grep startup logs for 'provider skipped (config error)' — the config_path attr names the broken entry","Verify secrets merging populates api_keys; empty strings register nothing"],"tags":["config","transcription","startup","missing-provider"],"backgroundTag":"config-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}