babysor/MockingBird · error · ValueError

Cue {cue.index}: either voice_id or reference_audio required

Error message

Cue {cue.index}: either voice_id or reference_audio required.

What it means

ValueError raised in _noiz_tts when a cue's voice-map entry provides neither reference_audio nor voice_id. Each cue must resolve to exactly one voice source for the Noiz backend.

Source

Thrown at skills/speak/scripts/render_timeline.py:282

        payload["save_voice"] = _bool_form(cfg["save_voice"])
    if "emo" in cfg and cfg["emo"] is not None:
        emo = cfg["emo"]
        payload["emo"] = emo if isinstance(emo, str) else json.dumps(emo)

    files = None
    ref_cleanup: Optional[Path] = None
    ref = cfg.get("reference_audio")
    if ref:
        ref_path, ref_cleanup = _resolve_reference_audio(ref, timeout)
        files = {
            "file": (
                ref_path.name,
                ref_path.open("rb"),
                "application/octet-stream",
            )
        }
    elif not cfg.get("voice_id"):
        raise ValueError(
            f"Cue {cue.index}: either voice_id or reference_audio required."
        )

    try:
        resp = requests.post(
            url, headers={"Authorization": api_key},
            data=payload, files=files, timeout=timeout,
        )
    finally:
        if files and files["file"][1]:
            files["file"][1].close()
        if ref_cleanup is not None:
            ref_cleanup.unlink(missing_ok=True)

    if resp.status_code != 200:
        raise RuntimeError(
            f"/text-to-speech cue {cue.index}: "
            f"status={resp.status_code}, body={resp.text}"

View on GitHub (pinned to 28dc5e14f1)

Solutions

  1. Add voice_id or reference_audio to the voice-map entry named in the error
  2. Check the cue's voice key matches a defined voice-map entry
  3. Validate the voice map at startup: every referenced entry has voice_id or reference_audio

Example fix

# before
{"evil": {"speed": 1.1}}
# after
{"evil": {"voice_id": "villain-01", "speed": 1.1}}
Defensive patterns

Strategy: validation

Validate before calling

for name, cfg in voice_map.items():
    assert cfg.get('voice_id') or cfg.get('reference_audio'), f'voice {name!r} lacks voice source'

Type guard

def cue_has_voice_source(cfg: dict) -> bool:
    return bool(cfg.get('voice_id') or cfg.get('reference_audio'))

Try / catch

try:
    _noiz_tts(cue, cfg, fmt, ...)
except ValueError as e:
    sys.exit(f'fix voice map: {e}')

Prevention

When it happens

Trigger: A voice_map entry containing only options like speed or emotion but no voice identifiers, or a cue referencing a missing voice-map key that falls through to an empty config.

Common situations: Typo in the voice-map key so the cue's entry is an empty dict, partially written config files, or entries copied from another backend's schema.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of babysor/MockingBird@28dc5e14f1 (2026-08-27). Data as JSON: /api/errors/1a12782b6eee91b6. Report an issue: GitHub.