{"record":{"id":"f78127436c0278e9","repo":"jamiepine/voicebox","slug":"pass-exactly-one-of-audio-base64-or-audio-path","errorCode":null,"errorMessage":"Pass exactly one of `audio_base64` or `audio_path`.","messagePattern":"Pass exactly one of `audio_base64` or `audio_path`\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/mcp_server/tools.py","lineNumber":130,"sourceCode":"        finally:\n            db.close()\n\n    @mcp.tool(\n        name=\"voicebox.transcribe\",\n        description=(\n            \"Transcribe an audio clip to text using Voicebox's local Whisper. \"\n            \"Pass exactly one of `audio_base64` (bytes as base64) or \"\n            \"`audio_path` (absolute local file path — loopback callers only).\"\n        ),\n    )\n    async def voicebox_transcribe(\n        audio_base64: str | None = None,\n        audio_path: str | None = None,\n        language: str | None = None,\n        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:","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/mcp_server/tools.py#L112-L148","documentation":"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.","triggerScenarios":"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').","commonSituations":"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'.","solutions":["Supply exactly one of audio_base64 or audio_path with non-empty content.","For remote callers, always use audio_base64.","For loopback/local tooling, prefer audio_path to avoid the base64 encode/decode round trip."],"exampleFix":"// before\nvoicebox_transcribe(audio_base64=b64, audio_path=\"/tmp/a.wav\")\n// after\nvoicebox_transcribe(audio_base64=b64)","handlingStrategy":"validation","validationCode":"has_b64 = bool(audio_base64)\nhas_path = bool(audio_path)\nif has_b64 == has_path:\n    raise ValueError(\"Supply exactly one of audio_base64 or audio_path.\")\nawait voicebox_transcribe(audio_base64=audio_base64, audio_path=audio_path)","typeGuard":"def has_exactly_one_audio_source(b64: str | None, path: str | None) -> bool:\n    return bool(b64) != bool(path)","tryCatchPattern":"try:\n    await voicebox_transcribe(audio_base64=audio_base64, audio_path=audio_path)\nexcept ValueError as exc:\n    if \"exactly one of\" in str(exc):\n        # pick the channel you actually have and retry\n        if audio_base64:\n            await voicebox_transcribe(audio_base64=audio_base64)\n        elif audio_path:\n            await voicebox_transcribe(audio_path=audio_path)\n    else:\n        raise","preventionTips":["Use mutually exclusive parameters at the client API (one non-null) rather than two optionals.","Treat empty string as 'not supplied' explicitly before calling.","Document that base64 is the universal channel and audio_path is loopback-only."],"tags":["mcp","validation","transcription","argument-validation"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}