microsoft/autogen · error · ValueError
audio_output_path must be within the current working directo
Error message
audio_output_path must be within the current working directory.
What it means
Thrown by extract_audio() in autogen_ext.agents.video_surfer.tools when the resolved (realpath) audio_output_path does not lie inside the process's current working directory. This is a deliberate security guard: because the path is handed to ffmpeg, allowing absolute paths or ../ segments would let an LLM-directed call write .mp3 files anywhere on disk. The check uses os.path.realpath on both sides, so symlinks pointing outside the cwd are also rejected.
Source
Thrown at python/packages/autogen-ext/src/autogen_ext/agents/video_surfer/tools.py:38
:param audio_output_path: Path to save the extracted audio file (must end with .mp3).
:return: Confirmation message with the path to the saved audio file.
"""
import os
import re
# Reject URLs to prevent SSRF via ffmpeg
if re.match(r"^[a-zA-Z][a-zA-Z0-9+\-.]*://", video_path):
raise ValueError("video_path must be a local file path, not a URL.")
# Enforce .mp3 extension to prevent writing arbitrary file types
if not audio_output_path.lower().endswith(".mp3"):
raise ValueError("audio_output_path must end with .mp3.")
# Prevent path traversal — output must stay within the current working directory
cwd = os.path.realpath(os.getcwd())
output_real = os.path.realpath(audio_output_path)
if not output_real.startswith(cwd + os.sep) and output_real != cwd:
raise ValueError("audio_output_path must be within the current working directory.")
(ffmpeg.input(video_path).output(audio_output_path, format="mp3").run(quiet=True, overwrite_output=True)) # type: ignore
return f"Audio extracted and saved to {audio_output_path}."
def transcribe_audio_with_timestamps(audio_path: str) -> str:
"""
Transcribes the audio file with timestamps using the Whisper model.
:param audio_path: Path to the audio file.
:return: Transcription with timestamps.
"""
model = whisper.load_model("base") # type: ignore
result: Dict[str, Any] = model.transcribe(audio_path, task="transcribe", language="en", verbose=False) # type: ignore
segments: List[Dict[str, Any]] = result["segments"]
transcription_with_timestamps = ""
View on GitHub (pinned to 027ecf0a37)
Solutions
- Pass a relative output path, e.g. extract_audio('video.mp4', 'audio.mp3'), so it resolves under os.getcwd()
- Build the path from the cwd explicitly: os.path.join(os.getcwd(), 'audio.mp3')
- If a custom directory is required, os.chdir() into it before calling extract_audio
- Verify with os.path.realpath(audio_output_path).startswith(os.path.realpath(os.getcwd()) + os.sep) before calling
Example fix
// before
extract_audio('input/video.mp4', '/tmp/episode_audio.mp3') # ValueError
// after
import os
extract_audio('input/video.mp4', os.path.join(os.getcwd(), 'episode_audio.mp3')) Defensive patterns
Strategy: validation
Validate before calling
import os
def safe_output_path(p: str) -> bool:
cwd = os.path.realpath(os.getcwd())
out = os.path.realpath(p)
return out == cwd or out.startswith(cwd + os.sep) and out.lower().endswith('.mp3') Type guard
def is_cwd_relative_mp3(path: str) -> bool:
import os
real = os.path.realpath(path)
return real.lower().endswith('.mp3') and real.startswith(os.path.realpath(os.getcwd()) + os.sep) Try / catch
try:
result = extract_audio(video, out)
except ValueError as e:
# e.message names which rule failed (url / extension / cwd); fix the path accordingly
out = os.path.join(os.getcwd(), 'audio.mp3')
result = extract_audio(video, out) Prevention
- Always build output paths with os.path.join(os.getcwd(), name)
- Never pass absolute temp dirs like /tmp to extract_audio
- Keep the .mp3 extension; the guard rejects other suffixes first
When it happens
Trigger: Calling extract_audio(video_path, audio_output_path) with an absolute output path like /tmp/out.mp3, a path with traversal segments like ../shared/audio.mp3, a relative path that escapes the cwd after realpath resolution, or a symlink inside the cwd that resolves to a directory outside it.
Common situations: Agents running from a different working directory than expected (e.g. notebook kernel cwd vs. notebook location), reusing paths returned by other tools that are absolute, or a host process whose os.getcwd() is a system directory. Also triggered when the caller chdir'd after computing the output path.
Related errors
- audio_output_path must end with .mp3.
- video_path must be a local file path, not a URL.
- Timestamp {timestamp:.2f}s is out of range [0s, {duration:.2
- Failed to list MCP prompts
- Failed to get MCP prompt
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/3a777a708fc943aa.
Report an issue: GitHub.