jamiepine/voicebox · error · ValueError
Invalid audio_base64: {exc}
Error message
Invalid audio_base64: {exc} What it means
Raised by voicebox_transcribe when b64.b64decode(audio_base64, validate=True) throws — i.e. audio_base64 is not legal base64. The original exception is chained (from exc) and surfaced as 'Invalid audio_base64: <reason>'.
Source
Thrown at backend/mcp_server/tools.py:158
"`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:
raise ValueError(
f"File exceeds {MAX_TRANSCRIBE_BYTES // (1024 * 1024)} MB limit."
)
return await _transcribe_file(path, language, model)
# Base64 mode: decode into a temp file, transcribe, clean up.
try:
raw = b64.b64decode(audio_base64, validate=True)
except Exception as exc:
raise ValueError(f"Invalid audio_base64: {exc}") from exc
if len(raw) > MAX_TRANSCRIBE_BYTES:
raise ValueError(
f"Audio exceeds {MAX_TRANSCRIBE_BYTES // (1024 * 1024)} MB limit."
)
with tempfile.NamedTemporaryFile(
suffix=".wav", delete=False
) as tmp:
tmp.write(raw)
tmp_path = Path(tmp.name)
try:
return await _transcribe_file(tmp_path, language, model)
finally:
tmp_path.unlink(missing_ok=True)
@mcp.tool(
name="voicebox.list_captures",
description=(
"List recent voice captures (dictations, recordings, uploads) "View on GitHub (pinned to 51f49dea19)
Solutions
- Encode the bytes with standard base64 on the caller side: base64.b64encode(data).decode().
- Strip any 'data:...;base64,' prefix before sending.
- Ensure correct padding (= or ==) and the standard (+/) alphabet, or pre-convert from urlsafe.
- Send the whole payload — avoid truncation by transport limits.
Example fix
// before
voicebox_transcribe(audio_base64=raw_bytes_str)
// after
voicebox_transcribe(audio_base64=base64.b64encode(raw_bytes).decode('ascii')) Defensive patterns
Strategy: validation
Validate before calling
import base64 # will raise here if invalid, instead of inside the tool raw = base64.b64decode(audio_base64, validate=True) await voicebox_transcribe(audio_base64=audio_base64)
Type guard
def is_valid_base64(value: str | None) -> bool:
import base64
if not isinstance(value, str) or not value:
return False
try:
base64.b64decode(value, validate=True)
return True
except Exception:
return False Try / catch
try:
await voicebox_transcribe(audio_base64=audio_base64)
except ValueError as exc:
if "Invalid audio_base64" in str(exc):
# strip data: URI prefix / re-pad, then retry
clean = audio_base64.split(",", 1)[-1]
clean += "=" * (-len(clean) % 4)
await voicebox_transcribe(audio_base64=clean)
else:
raise Prevention
- Strip any 'data:audio/...;base64,' prefix before sending.
- Use standard (not urlsafe) base64 with correct padding.
- Encode on the caller with base64.b64encode(data).decode('ascii').
When it happens
Trigger: Sending raw bytes instead of base64; a data-URI prefix ('data:audio/wav;base64,...') left on the string; wrong alphabet (URL-safe vs standard); truncated payload; non-ASCII characters or whitespace in the middle of the string.
Common situations: Frontend forgetting to base64-encode a Blob; copy-paste truncation; padding ('=') stripped; using base64.urlsafe_b64encode on the client but standard decode on the server.
Related errors
- Pass exactly one of `audio_base64` or `audio_path`.
- `audio_path` must be absolute.
- Audio exceeds {MAX_TRANSCRIBE_BYTES // (1024 * 1024)} MB lim
- Invalid STT model '{model_size}'. Must be one of: {', '.join
- `audio_path` is only available to loopback callers — remote
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/ff213850fea87f17.
Report an issue: GitHub.