{"record":{"id":"ff213850fea87f17","repo":"jamiepine/voicebox","slug":"invalid-audio-base64-exc","errorCode":null,"errorMessage":"Invalid audio_base64: {exc}","messagePattern":"Invalid audio_base64: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/mcp_server/tools.py","lineNumber":158,"sourceCode":"                    \"`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(\n            suffix=\".wav\", delete=False\n        ) as tmp:\n            tmp.write(raw)\n            tmp_path = Path(tmp.name)\n        try:\n            return await _transcribe_file(tmp_path, language, model)\n        finally:\n            tmp_path.unlink(missing_ok=True)\n\n    @mcp.tool(\n        name=\"voicebox.list_captures\",\n        description=(\n            \"List recent voice captures (dictations, recordings, uploads) \"","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/mcp_server/tools.py#L140-L176","documentation":"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>'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvoicebox_transcribe(audio_base64=raw_bytes_str)\n// after\nvoicebox_transcribe(audio_base64=base64.b64encode(raw_bytes).decode('ascii'))","handlingStrategy":"validation","validationCode":"import base64\n# will raise here if invalid, instead of inside the tool\nraw = base64.b64decode(audio_base64, validate=True)\nawait voicebox_transcribe(audio_base64=audio_base64)","typeGuard":"def is_valid_base64(value: str | None) -> bool:\n    import base64\n    if not isinstance(value, str) or not value:\n        return False\n    try:\n        base64.b64decode(value, validate=True)\n        return True\n    except Exception:\n        return False","tryCatchPattern":"try:\n    await voicebox_transcribe(audio_base64=audio_base64)\nexcept ValueError as exc:\n    if \"Invalid audio_base64\" in str(exc):\n        # strip data: URI prefix / re-pad, then retry\n        clean = audio_base64.split(\",\", 1)[-1]\n        clean += \"=\" * (-len(clean) % 4)\n        await voicebox_transcribe(audio_base64=clean)\n    else:\n        raise","preventionTips":["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')."],"tags":["mcp","base64","validation","transcription"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}