{"record":{"id":"3a2b98b12f7cb727","repo":"microsoft/autogen","slug":"audio-output-path-must-end-with-mp3","errorCode":null,"errorMessage":"audio_output_path must end with .mp3.","messagePattern":"audio_output_path must end with \\.mp3\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py","lineNumber":32,"sourceCode":"\ndef extract_audio(video_path: str, audio_output_path: str) -> str:\n    \"\"\"\n    Extracts audio from a video file and saves it as an MP3 file.\n\n    :param video_path: Path to the video file (must be a local file path, not a URL).\n    :param audio_output_path: Path to save the extracted audio file (must end with .mp3).\n    :return: Confirmation message with the path to the saved audio file.\n    \"\"\"\n    import os\n    import re\n\n    # Reject URLs to prevent SSRF via ffmpeg\n    if re.match(r\"^[a-zA-Z][a-zA-Z0-9+\\-.]*://\", video_path):\n        raise ValueError(\"video_path must be a local file path, not a URL.\")\n\n    # Enforce .mp3 extension to prevent writing arbitrary file types\n    if not audio_output_path.lower().endswith(\".mp3\"):\n        raise ValueError(\"audio_output_path must end with .mp3.\")\n\n    # Prevent path traversal — output must stay within the current working directory\n    cwd = os.path.realpath(os.getcwd())\n    output_real = os.path.realpath(audio_output_path)\n    if not output_real.startswith(cwd + os.sep) and output_real != cwd:\n        raise ValueError(\"audio_output_path must be within the current working directory.\")\n\n    (ffmpeg.input(video_path).output(audio_output_path, format=\"mp3\").run(quiet=True, overwrite_output=True))  # type: ignore\n    return f\"Audio extracted and saved to {audio_output_path}.\"\n\n\ndef transcribe_audio_with_timestamps(audio_path: str) -> str:\n    \"\"\"\n    Transcribes the audio file with timestamps using the Whisper model.\n\n    :param audio_path: Path to the audio file.\n    :return: Transcription with timestamps.\n    \"\"\"","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py#L14-L50","documentation":"extract_audio in video_surfer hard-codes MP3 output (ffmpeg format=mp3) and enforces it by rejecting any audio_output_path that does not end in .mp3 (case-insensitive). Allowing arbitrary extensions would let callers write other file types, so the extension acts as both a format contract and a write-scope guard (paired with a cwd path-traversal check).","triggerScenarios":"extract_audio(\"clip.mp4\", \"/tmp/out/clip.wav\") — any output path whose lowercase form does not end with .mp3, including .MP3-safe variants like clip.mp4 or clip.","commonSituations":"LLM tool calls proposing .wav/.m4a outputs; pipelines that derive the output name from the input name without rewriting the extension.","solutions":["Rename the output to end with .mp3: pass \"/tmp/out/clip.mp3\".","If you need another format, call ffmpeg directly (ffmpeg.input(...).output(path, format=...)) rather than this tool.","In agent prompts, specify the output path convention *.mp3 for this tool."],"exampleFix":"# before\nextract_audio(\"/tmp/work/clip.mp4\", \"/tmp/work/clip.wav\")\n\n# after\nextract_audio(\"/tmp/work/clip.mp4\", \"/tmp/work/clip.mp3\")","handlingStrategy":"validation","validationCode":"import os\n\ndef mp3_output(path: str) -> str:\n    root, _ = os.path.splitext(path)\n    return root + \".mp3\"\n\naudio_out = mp3_output(audio_output_path)  # always .mp3","typeGuard":"def is_mp3_path(p: str) -> bool:\n    return isinstance(p, str) and p.lower().endswith(\".mp3\")","tryCatchPattern":null,"preventionTips":["Derive output names by replacing the extension with .mp3, never reusing the input extension.","For other formats, call ffmpeg directly instead of this tool.","State the *.mp3 convention in agent instructions."],"tags":["video-surfer","file-extension","validation","ffmpeg"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}