jamiepine/voicebox · error · RuntimeError
Unable to split unstable TTS output for retry
Error message
Unable to split unstable TTS output for retry
What it means
Raised by generate_one() in backend/utils/chunked_tts.py when the runaway detector flagged a chunk, the retry budget and minimum-size checks passed, but split_text_into_chunks(chunk_text, retry_max_chars) returned only a single chunk. The retry strategy depends on splitting the unstable chunk into strictly smaller pieces; if the splitter cannot subdivide it (e.g. no sentence/whitespace boundaries within the budget), retry is impossible and the function aborts.
Source
Thrown at backend/utils/chunked_tts.py:275
) -> tuple[np.ndarray, int]:
chunk_audio, chunk_sr = await backend.generate(
chunk_text,
voice_prompt,
language,
chunk_seed,
instruct,
)
if runaway_detector is not None and runaway_detector(chunk_audio, chunk_sr):
if retry_depth >= MAX_RUNAWAY_RETRIES or len(chunk_text) <= MIN_RUNAWAY_RETRY_CHARS:
raise RuntimeError(
"TTS output remained unstable after retrying smaller text chunks"
)
retry_max_chars = max(MIN_RUNAWAY_RETRY_CHARS, len(chunk_text) // 2)
retry_chunks = split_text_into_chunks(chunk_text, retry_max_chars)
if len(retry_chunks) <= 1:
raise RuntimeError("Unable to split unstable TTS output for retry")
logger.warning(
"Detected unstable TTS output for %d chars; retrying as %d smaller chunks",
len(chunk_text),
len(retry_chunks),
)
retry_audio: list[np.ndarray] = []
for i, retry_text in enumerate(retry_chunks):
retry_seed = (
chunk_seed + ((retry_depth + 1) * 1000) + i
if chunk_seed is not None
else None
)
audio, sample_rate = await generate_one(
retry_text,
retry_seed,
retry_depth + 1,
)View on GitHub (pinned to 51f49dea19)
Solutions
- Pre-split the input on whitespace or character count before passing to chunked TTS so no single chunk is unsplittable.
- Strip or break up long unbroken tokens (URLs, base64) in the source text.
- Provide a custom trim_fn or preprocessor that normalizes problematic text.
- For CJK/no-space languages, configure the chunker to split on characters, not sentence/word boundaries.
Example fix
// before: a chunk that is one long token run cannot be split
audio, sr = await generate_chunked_tts(backend, very_long_token_run, voice_prompt, ...)
// after: break long token runs before synthesis
text = re.sub(r'(\S{200})', r'\1 ', text) // insert breakable spaces
audio, sr = await generate_chunked_tts(backend, text, voice_prompt, ...) Defensive patterns
Strategy: validation
Validate before calling
import re
def is_splittable(text: str, max_chars: int) -> bool:
# ensure there is at least one breakable boundary within max_chars
broken = re.findall(r'.{1,' + str(max_chars) + r'}', text)
return len(broken) > 1 Try / catch
try:
audio, sr = await generate_chunked_tts(backend, text, voice_prompt, ...)
except RuntimeError as e:
if 'Unable to split unstable TTS output' in str(e):
# insert breakable spaces into long token runs and retry
text = re.sub(r'(\S{120})', r'\1 ', text)
audio, sr = await generate_chunked_tts(backend, text, voice_prompt, ...)
else:
raise Prevention
- Pre-process input to break long unbroken token runs (URLs, base64, CJK) before synthesis.
- For languages without whitespace, configure the chunker for character-level splits.
- Sanitize text to insert spaces after very long non-space sequences.
When it happens
Trigger: A chunk whose text has no splittable boundary under retry_max_chars — a single very long word/URL/token run, or text without sentence punctuation/whitespace where the splitter cannot break it; chunk length just over MIN_RUNAWAY_RETRY_CHARS so halving still yields one piece per the splitter's rules.
Common situations: Inputs containing very long unbroken token strings (URLs, base64, CJK without spaces, code); text with no terminal punctuation that the sentence-aware splitter keys on; languages without whitespace word boundaries.
Related errors
- TTS output remained unstable after retrying smaller text chu
- HTTP error! status: ${response.status}
- HTTP ${res.status}
- Navigator API is not available. This might be a Tauri config
- Microphone access is not available. Please ensure: 1. The ap
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/275769ae2b0bce32.
Report an issue: GitHub.