Is there any way to not crash the call when we get...
# ask-ai
r
Is there any way to not crash the call when we get this error? no audio frames were pushed for text:
t
Thanks for reaching out, Trevor. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — you’re asking how to avoid crashing the call when you see the error “no audio frames were pushed for text.” Here are practical ways to prevent that from taking down the session and keep audio playback graceful. What to try next • Use pre-synthesized audio with session.say Provide an
audio
stream (pre-recorded or pre-rendered frames) when calling
session.say()
so playback doesn’t depend on live TTS. This ensures audio frames exist even if TTS fails. • Add fallback/error handling in your TTS node Catch exceptions in your TTS pipeline and either: • yield a short silence frame, or • yield a fallback prerecorded clip, or • log the error and continue without raising an exception that would abort the session. • Validate TTS setup before speaking Confirm the TTS model/plugin is initialized and supports the requested voice. If initialization fails, switch to fallback audio instead of attempting live synthesis. • Monitor and recover automatically Detect when no frames are emitted (timeout or zero-frame output) and trigger a recovery path: play fallback audio, retry synthesis once, or skip the utterance without throwing an unhandled error. If you want, tell me which method you’re using now (calling
session.say()
directly, a custom
tts_node
, or a TTS plugin/model name) and I’ll give a concise code example you can drop into your pipeline. Sources: How to Set Up Speech-to-Text Input with Text-Only Output in LiveKit Agents | Agent speech and audio | LiveKit docs | Pipeline nodes and hooks | LiveKit docs | Text-to-speech (TTS) models | LiveKit Docs
r
If my LLM says: "" or " ", I want to not crash -- I want to be able to catch this and move on
t
You're asking how to catch empty or whitespace-only LLM outputs (e.g., "" or " ") so TTS doesn't crash the call. Below are concise, practical patterns you can use. Tell me which language/framework you use if you want a tailored snippet. 1) Validate LLM text before TTS • Trim and check length; if empty, skip or use fallback. Example logic (pseudocode):
Copy code
text = llm_response.strip()
if not text:
    # skip speaking or play fallback audio
    await session.say(audio=fallback_audio)
else:
    await session.say(text=text)
2) Use a fallback audio clip or silence • Play a short prerecorded message or silence so the pipeline always receives frames. • Silence can be a single generated audio frame or a short silent stream. 3) Defensive TTS wrapper • Wrap TTS calls so they never raise out-of-band exceptions to the session; return silence/fallback on error.
Copy code
async def safe_say(session, text):
    text = (text or "").strip()
    if not text:
        await session.say(audio=fallback_audio)  # or return
        return
    try:
        await session.say(text=text)
    except Exception:
        await session.say(audio=fallback_audio)
4) In custom
tts_node
implementations • If the LLM yields empty text, yield silence or fallback frames instead of raising. • Catch synth errors and yield silent frames to keep stream alive. 5) Monitoring / metrics • Log occurrences of empty outputs and count retries to decide when to alter model prompts or fallback behavior. If you tell me which SDK/language you use (Python/JS) and whether you prefer skipping, silence, or a spoken fallback, I’ll give a copy-paste snippet for your code.
r
python. I don't want fallback audio, I want to just no-op and continue
t
Got it — you want a Python no-op when the LLM returns empty/whitespace so the call keeps running. Below is a concise pattern you can drop into your code.
Copy code
async def safe_say(session, text):
    # Normalize and skip empty/whitespace-only responses
    if not (text or "").strip():
        return  # no-op and continue

    # Normal speak path
    await session.say(text=text)
If you use a custom
tts_node
generator, do the same inside the generator:
Copy code
async def tts_node(text_iter, model_settings):
    async for chunk in text_iter:
        if not (chunk or "").strip():
            continue  # skip this chunk and keep streaming
        async for frame in synthesize_frames(chunk, model_settings):
            yield frame
Use these patterns wherever you accept LLM output before calling TTS; this prevents crashes by skipping empty inputs and continuing the session. Would you like a version with logging or timeout handling added?