jamiepine/voicebox · error · ValueError

Pass exactly one of `audio_base64` or `audio_path`.

Error message

Pass exactly one of `audio_base64` or `audio_path`.

What it means

Raised by voicebox_transcribe when both audio_base64 and audio_path are passed, or when neither is. The check is bool(audio_base64) == bool(audio_path), so exactly one input channel must be truthy: base64 bytes for any caller, or an absolute local file path restricted to loopback callers.

Source

Thrown at backend/mcp_server/tools.py:130

        finally:
            db.close()

    @mcp.tool(
        name="voicebox.transcribe",
        description=(
            "Transcribe an audio clip to text using Voicebox's local Whisper. "
            "Pass exactly one of `audio_base64` (bytes as base64) or "
            "`audio_path` (absolute local file path — loopback callers only)."
        ),
    )
    async def voicebox_transcribe(
        audio_base64: str | None = None,
        audio_path: str | None = None,
        language: str | None = None,
        model: str | None = None,
    ) -> dict[str, Any]:
        if bool(audio_base64) == bool(audio_path):
            raise ValueError(
                "Pass exactly one of `audio_base64` or `audio_path`."
            )

        # Absolute-path mode: validate and transcribe in place. Restricted
        # to loopback callers so a Voicebox bound on 0.0.0.0 doesn't double
        # as an unauthenticated arbitrary-local-file read primitive.
        if audio_path is not None:
            if not request_is_loopback():
                raise ValueError(
                    "`audio_path` is only available to loopback callers — "
                    "remote callers must use `audio_base64`."
                )
            path = Path(audio_path)
            if not path.is_absolute():
                raise ValueError("`audio_path` must be absolute.")
            if not path.is_file():
                raise ValueError(f"File not found: {audio_path}")
            if path.stat().st_size > MAX_TRANSCRIBE_BYTES:

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Supply exactly one of audio_base64 or audio_path with non-empty content.
  2. For remote callers, always use audio_base64.
  3. For loopback/local tooling, prefer audio_path to avoid the base64 encode/decode round trip.

Example fix

// before
voicebox_transcribe(audio_base64=b64, audio_path="/tmp/a.wav")
// after
voicebox_transcribe(audio_base64=b64)
Defensive patterns

Strategy: validation

Validate before calling

has_b64 = bool(audio_base64)
has_path = bool(audio_path)
if has_b64 == has_path:
    raise ValueError("Supply exactly one of audio_base64 or audio_path.")
await voicebox_transcribe(audio_base64=audio_base64, audio_path=audio_path)

Type guard

def has_exactly_one_audio_source(b64: str | None, path: str | None) -> bool:
    return bool(b64) != bool(path)

Try / catch

try:
    await voicebox_transcribe(audio_base64=audio_base64, audio_path=audio_path)
except ValueError as exc:
    if "exactly one of" in str(exc):
        # pick the channel you actually have and retry
        if audio_base64:
            await voicebox_transcribe(audio_base64=audio_base64)
        elif audio_path:
            await voicebox_transcribe(audio_path=audio_path)
    else:
        raise

Prevention

When it happens

Trigger: Calling voicebox_transcribe() with no arguments; passing both audio_base64 and audio_path; passing an empty string for one and a real value for the other (empty is falsy and counts as 'not supplied').

Common situations: Client defaults both params to None and forgets to set one; pipeline wires base64 and path simultaneously 'just in case'; an empty/blank base64 string treated as 'set'.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/f78127436c0278e9. Report an issue: GitHub.