i have two stt main stt = sarvam fallback stt = az...
# ask-ai
a
i have two stt main stt = sarvam fallback stt = azure this is how im returning the stt
Copy code
def create_stt(self, agent_info: AgentInfo):
    return stt.FallbackAdapter([
        _build_sarvam_stt_instance(self, agent_info),
        _build_azure_stt_instance(self, agent_info),
    ])
Copy code
def _build_sarvam_stt_instance(provider: STTProvider, agent_info: AgentInfo):
    stt_details: STTDetails = agent_info.config.stt_details
    return sarvam.STT(
        model=agent_info.model_values.stt.model or provider.get_config_value('sarvam', 'model', ),
        language=stt_details.language or provider.get_config_value('sarvam', 'language', ),
        mode=stt_details.mode,
        prompt=stt_details.prompt or provider.get_config_value('sarvam', 'prompt', ),
        high_vad_sensitivity=stt_details.high_vad_sensitivity or provider.get_config_value(
            'sarvam', 'high_vad_sensitivity', ),
        sample_rate=stt_details.sample_rate or provider.get_config_value('sarvam', 'sample_rate', 'int'),
        flush_signal=stt_details.flush_signal or provider.get_config_value('sarvam', 'flush_signal', ),
        input_audio_codec=stt_details.input_audio_codec or provider.get_config_value('sarvam', 'input_audio_codec', ),
    )
Copy code
def _build_azure_stt_instance(provider: STTProvider, agent_info: AgentInfo) -> azure_stt_1_3x.STT:
    stt_details: STTDetails = agent_info.config.stt_details
    profanity_option = AzureSTTProvider.get_profanity_option(
        stt_details.profanity or provider.get_config_value('azure', 'profanity', ))

    languages = stt_details.languages
    if languages is None:
        languages = []
    single_language = stt_details.language
    combined_languages = [
        lang.strip()
        for lang in (languages + ([single_language] if single_language else []))
        if lang and lang.strip()
    ]

    return azure_stt_1_3x.STT(
        speech_key=stt_details.speech_key or provider.get_config_value('azure', 'speech_key_env', 'env'),
        speech_region=stt_details.speech_region or provider.get_config_value('azure', 'speech_region_env', 'env'),
        speech_auth_token=stt_details.speech_auth_token or provider.get_config_value('azure', 'speech_auth_token', ),
        sample_rate=stt_details.sample_rate or provider.get_config_value('azure', 'sample_rate', 'int'),
        num_channels=stt_details.num_channels or provider.get_config_value('azure', 'num_channels', 'int'),
        segmentation_silence_timeout_ms=stt_details.segmentation_silence_timeout_ms or provider.get_config_value(
            'azure', 'segmentation_silence_timeout_ms', 'int'),
        segmentation_max_time_ms=stt_details.segmentation_max_time_ms or provider.get_config_value(
            'azure', 'segmentation_max_time_ms', 'int'),
        segmentation_strategy=stt_details.segmentation_strategy or provider.get_config_value(
            'azure', 'segmentation_strategy', ),
        language=combined_languages,
        profanity=profanity_option,
    )
this is the code suppose i have passed sarvam config with language = hiiii "unhandled exception while running the job task\nTraceback (most recent call last):\n File \"/Users/harshita.patil/whizdm-dev/livekit-agent/.venv/lib/python3.11/site-packages/opentelemetry/util/_decorator.py\", line 71, in async_wrapper\n return await func(*args, **kwargs) # type: ignore\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/Users/harshita.patil/whizdm-dev/livekit-agent/.venv/lib/python3.11/site-packages/livekit/agents/ipc/job_proc_lazy_main.py\", line 306, in _traceable_entrypoint\n await self._job_entrypoint_fnc(job_ctx)\n File \"/Users/harshita.patil/whizdm-dev/livekit-agent/agents/agent.py\", line 1052, in entrypoint\n @session.on(\"metrics_collected\")\n ^^^^^^^^^^\nAttributeError: 'NoneType' object has no attribute 'on'", "level": "ERROR", "name": "livekit.agents", "exc_info": "Traceback (most recent call last):\n File \"/Users/harshita.patil/whizdm-dev/livekit-agent/.venv/lib/python3.11/site-packages/opentelemetry/util/_decorator.py\", line 71, in async_wrapper\n return await func(*args, **kwargs) # type: ignore\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/Users/harshita.patil/whizdm-dev/livekit-agent/.venv/lib/python3.11/site-packages/livekit/agents/ipc/job_proc_lazy_main.py\", line 306, in _traceable_entrypoint\n await self._job_entrypoint_fnc(job_ctx)\n File \"/Users/harshita.patil/whizdm-dev/livekit-agent/agents/agent.py\", line 1052, in entrypoint\n @session.on(\"metrics_collected\")\n ^^^^^^^^^^\nAttributeError: 'NoneType' object has no attribute 'on'", "pid": 59798, "job_id": "AJ_W2xx6dXw2263", "room_id": "RM_y3sADj829qxm", "timestamp": "2026-04-15T094159.954416+00:00"} {"message": it directly fails the stt and terminate the session instead it should switch to the fallback
✅ 1
t
Thanks for reaching out, Harshita. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — you’re saying the Sarvam STT is passed an invalid language ("hiiii"), the agent errors with
AttributeError: 'NoneType' object has no attribute 'on'
, and instead of falling back to Azure the session is terminated. I’ll help troubleshoot and get fallback working. First quick checks (please confirm): • Did you validate the Sarvam language value (e.g., a supported ISO code)? If not, please try a known-good language code. • Can you share whether any Sarvam or Azure required env vars / keys are missing or invalid? Immediate actionable steps to isolate and fix the fallback behavior: 1. Prevent initialization exceptions from killing the session ◦ Wrap each STT instance creation in a try/except and log failures. If an instance fails to construct, skip it rather than letting the exception propagate. ◦ Example pattern: ▪︎ Try to build Sarvam; on exception log error and continue. ▪︎ Try to build Azure; on exception log error and continue. ▪︎ If no instances remain, fail gracefully with a clear message. 1. Verify each STT instance independently ◦ Initialize and test Sarvam and Azure separately (outside of
FallbackAdapter
) to confirm they construct and start without errors. ◦ This will reveal if an invalid language or missing credential causes immediate failure. 1. Validate configuration values early ◦ Add validation for language codes and required keys when reading
agent_info.config.stt_details
. Reject invalid values with a clear error before initializing STT objects. ◦ For Sarvam: ensure
language
is a supported code. For Azure: ensure
speech_key
,
speech_region
, etc., are present. 1. Ensure
FallbackAdapter
gets only valid instances ◦ Build a list of successfully-initialized STT instances, then pass that list to
FallbackAdapter
. If the list is empty, handle that as a session setup failure (with a descriptive error), not an unhandled exception. 1. Investigate the
'NoneType' object has no attribute 'on'
location ◦ That traceback shows
@session.on("metrics_collected")
where
session
is None. This likely means session initialization was aborted by an earlier exception (e.g., STT init). After you add defensive handling around STT construction, re-run and confirm
session
is created successfully. If you’d like, share: • The updated code after adding try/except around STT builds, or • The Sarvam language value and relevant log lines when you build Sarvam. I can then suggest a concrete code snippet to integrate into your builder logic and confirm the fallback will work. Sources: Build a multilingual voice agent that automatically switches languages | Li... | Azure OpenAI LLM plugin guide | LiveKit Documentation | examples/voice_agents | livekit/livekit_composite | DeepWiki | Sarvam STT plugin guide | LiveKit Documentation | Azure Speech STT plugin guide | LiveKit Documentation, with interactive elements
a
can you give example
t
Thanks — below is a concise example showing defensive construction of STT instances, validation of language, and building the FallbackAdapter only with successfully initialized providers. It logs errors, skips invalid providers, and ensures the session isn't aborted by an unhandled exception.
Copy code
import logging
from typing import List

logger = logging.getLogger(__name__)

def _is_valid_language(lang: str) -> bool:
    # replace with real validation (e.g., check against supported ISO codes)
    return bool(lang and len(lang) >= 2)

def create_stt(self, agent_info: AgentInfo):
    stt_details = agent_info.config.stt_details
    stt_instances: List[BaseSTT] = []

    # Try Sarvam first
    try:
        lang = stt_details.language or self.get_config_value('sarvam', 'language')
        if not _is_valid_language(lang):
            raise ValueError(f"invalid sarvam language: {lang!r}")

        sarvam_instance = _build_sarvam_stt_instance(self, agent_info)
        stt_instances.append(sarvam_instance)
        logger.info("Sarvam STT initialized")
    except Exception as e:
        logger.exception("Sarvam STT init failed, will try fallback: %s", e)

    # Then Azure
    try:
        # Validate at least one language for Azure if required
        azure_langs = (stt_details.languages or []) + ([stt_details.language] if stt_details.language else [])
        if azure_langs and not all(_is_valid_language(l) for l in azure_langs):
            raise ValueError(f"invalid azure languages: {azure_langs!r}")

        azure_instance = _build_azure_stt_instance(self, agent_info)
        stt_instances.append(azure_instance)
        logger.info("Azure STT initialized")
    except Exception as e:
        logger.exception("Azure STT init failed: %s", e)

    if not stt_instances:
        # No valid STT providers — handle gracefully (do not let exception crash session)
        logger.error("No STT providers available after validation. Proceeding without STT.")
        return None  # or return a NoOp STT implementation

    # Create FallbackAdapter with only valid instances
    return stt.FallbackAdapter(stt_instances)
If you want, I can: • Provide a NoOp STT example to return when no providers are available, or • Replace
_is_valid_language
with a real language-code check using a list you provide. Which would you prefer?, with interactive elements