jamiepine/voicebox · error · ValueError
`audio_path` must be absolute.
Error message
`audio_path` must be absolute.
What it means
Raised by voicebox_transcribe when audio_path is supplied but Path(audio_path).is_absolute() is False. Only absolute paths are accepted so the resolved file cannot be confused by the server's current working directory.
Source
Thrown at backend/mcp_server/tools.py:145
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:
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(View on GitHub (pinned to 51f49dea19)
Solutions
- Pass a fully resolved absolute path, e.g. str(Path(...).resolve()).
- Expand user and symlinks on the caller side before sending: Path(p).expanduser().resolve().
- Ensure the path uses the server's OS conventions (forward slashes on Linux).
Example fix
// before
voicebox_transcribe(audio_path="clips/hello.wav")
// after
voicebox_transcribe(audio_path=str(pathlib.Path("clips/hello.wav").resolve())) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
p = Path(audio_path).expanduser()
if not p.is_absolute():
p = p.resolve()
await voicebox_transcribe(audio_path=str(p)) Type guard
def is_absolute_audio_path(value: str) -> bool:
from pathlib import Path
return isinstance(value, str) and Path(value).is_absolute() Try / catch
try:
await voicebox_transcribe(audio_path=audio_path)
except ValueError as exc:
if "must be absolute" in str(exc):
from pathlib import Path
await voicebox_transcribe(audio_path=str(Path(audio_path).resolve()))
else:
raise Prevention
- Always resolve() the path on the caller side before sending.
- Expand '~' and environment variables locally first.
- Use forward slashes and OS-appropriate roots matching the Voicebox host.
When it happens
Trigger: Passing a relative path like "audio/clip.wav" or "./clip.wav" as audio_path; a client joining a directory to a filename with a leading './'.
Common situations: Client building paths with os.path.join from a relative base; shell-style '~' not expanded (also not absolute); Windows-style drive paths on a Linux server.
Related errors
- Pass exactly one of `audio_base64` or `audio_path`.
- `audio_path` is only available to loopback callers — remote
- File not found: {audio_path}
- File exceeds {MAX_TRANSCRIBE_BYTES // (1024 * 1024)} MB limi
- Invalid audio_base64: {exc}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/cdc0f5af456aceb2.
Report an issue: GitHub.