{"record":{"id":"cdc0f5af456aceb2","repo":"jamiepine/voicebox","slug":"audio-path-must-be-absolute","errorCode":null,"errorMessage":"`audio_path` must be absolute.","messagePattern":"`audio_path` must be absolute\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/mcp_server/tools.py","lineNumber":145,"sourceCode":"        model: str | None = None,\n    ) -> dict[str, Any]:\n        if bool(audio_base64) == bool(audio_path):\n            raise ValueError(\n                \"Pass exactly one of `audio_base64` or `audio_path`.\"\n            )\n\n        # Absolute-path mode: validate and transcribe in place. Restricted\n        # to loopback callers so a Voicebox bound on 0.0.0.0 doesn't double\n        # as an unauthenticated arbitrary-local-file read primitive.\n        if audio_path is not None:\n            if not request_is_loopback():\n                raise ValueError(\n                    \"`audio_path` is only available to loopback callers — \"\n                    \"remote callers must use `audio_base64`.\"\n                )\n            path = Path(audio_path)\n            if not path.is_absolute():\n                raise ValueError(\"`audio_path` must be absolute.\")\n            if not path.is_file():\n                raise ValueError(f\"File not found: {audio_path}\")\n            if path.stat().st_size > MAX_TRANSCRIBE_BYTES:\n                raise ValueError(\n                    f\"File exceeds {MAX_TRANSCRIBE_BYTES // (1024 * 1024)} MB limit.\"\n                )\n            return await _transcribe_file(path, language, model)\n\n        # Base64 mode: decode into a temp file, transcribe, clean up.\n        try:\n            raw = b64.b64decode(audio_base64, validate=True)\n        except Exception as exc:\n            raise ValueError(f\"Invalid audio_base64: {exc}\") from exc\n        if len(raw) > MAX_TRANSCRIBE_BYTES:\n            raise ValueError(\n                f\"Audio exceeds {MAX_TRANSCRIBE_BYTES // (1024 * 1024)} MB limit.\"\n            )\n        with tempfile.NamedTemporaryFile(","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/mcp_server/tools.py#L127-L163","documentation":"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.","triggerScenarios":"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 './'.","commonSituations":"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.","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)."],"exampleFix":"// before\nvoicebox_transcribe(audio_path=\"clips/hello.wav\")\n// after\nvoicebox_transcribe(audio_path=str(pathlib.Path(\"clips/hello.wav\").resolve()))","handlingStrategy":"validation","validationCode":"from pathlib import Path\np = Path(audio_path).expanduser()\nif not p.is_absolute():\n    p = p.resolve()\nawait voicebox_transcribe(audio_path=str(p))","typeGuard":"def is_absolute_audio_path(value: str) -> bool:\n    from pathlib import Path\n    return isinstance(value, str) and Path(value).is_absolute()","tryCatchPattern":"try:\n    await voicebox_transcribe(audio_path=audio_path)\nexcept ValueError as exc:\n    if \"must be absolute\" in str(exc):\n        from pathlib import Path\n        await voicebox_transcribe(audio_path=str(Path(audio_path).resolve()))\n    else:\n        raise","preventionTips":["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."],"tags":["mcp","validation","filesystem","transcription"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}