{"record":{"id":"c4b23df19d8831b9","repo":"Panniantong/Agent-Reach","slug":"ffprobe-could-not-parse-a-valid-audio-duration","errorCode":null,"errorMessage":"ffprobe could not parse a valid audio duration","messagePattern":"ffprobe could not parse a valid audio duration","errorType":"exception","errorClass":"TranscribeError","httpStatus":null,"severity":"error","filePath":"agent_reach/transcribe.py","lineNumber":134,"sourceCode":"            \"ffprobe timed out while reading audio duration \"\n            f\"after {FFPROBE_TIMEOUT_SECONDS}s\"\n        ) from None\n    except OSError as exc:\n        raise TranscribeError(\n            f\"ffprobe could not read audio duration: {exc}\"\n        ) from exc\n\n    if proc.returncode != 0:\n        detail = proc.stderr.strip()[:300] or \"unknown ffprobe error\"\n        raise TranscribeError(\n            f\"ffprobe failed while reading audio duration: {detail}\"\n        )\n\n    raw_duration = proc.stdout.strip()\n    try:\n        duration = float(raw_duration)\n    except (TypeError, ValueError):\n        raise TranscribeError(\n            \"ffprobe could not parse a valid audio duration\"\n        ) from None\n    if not math.isfinite(duration) or duration <= 0:\n        raise TranscribeError(\n            \"ffprobe could not parse a valid positive audio duration\"\n        )\n    return duration\n\n\ndef _require_duration_within_budget(path: Path) -> float:\n    \"\"\"Reject audio that cannot fit within the bounded chunk budget.\"\"\"\n    duration = _probe_audio_duration(path)\n    if duration > MAX_AUDIO_SECONDS:\n        max_minutes = MAX_AUDIO_SECONDS // 60\n        raise TranscribeError(\n            f\"audio duration exceeds safety limit of {max_minutes} minutes\"\n        )\n    return duration","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/Panniantong/Agent-Reach/blob/93ae1d18c37b707dec053c7c4f9d91cd8ef8943d/agent_reach/transcribe.py#L116-L152","documentation":"Raised by _probe_audio_duration() in agent_reach/transcribe.py when ffprobe exits 0 but its stdout cannot be parsed as a float (float() raises TypeError/ValueError). The command requests only format=duration, so a missing or malformed duration line (e.g. 'N/A' or empty output for streams without duration metadata) hits this path. from None keeps the traceback clean.","triggerScenarios":"Live-recorded streams, some WAV/PCM files, or freshly created media where the container lacks a duration field, making ffprobe print 'N/A' or nothing.","commonSituations":"Microphone recordings produced by tools that omit header duration; pipe-sourced media; unusual containers ffprobe reports duration-less.","solutions":["Re-mux the file so duration is computed: ffmpeg -i in.wav -c copy out.m4a, then retry","Strip duration-less headers by re-encoding: ffmpeg -i in.webm out.m4a","Check manually: ffprobe -v error -show_entries format=duration -i file"],"exampleFix":"# before: duration prints 'N/A' -> TranscribeError\ntranscribe_audio(Path('live_stream.webm'))\n\n# after\nsubprocess.run(['ffmpeg', '-i', 'live_stream.webm', '-c', 'copy', 'fixed.m4a'])\ntranscribe_audio(Path('fixed.m4a'))","handlingStrategy":"validation","validationCode":"out = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', '-i', str(path)], capture_output=True, text=True).stdout.strip()\ntry:\n    d = float(out)\nexcept ValueError:\n    d = None  # re-mux before calling transcribe","typeGuard":"def has_parsable_duration(path) -> bool:\n    out = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', '-i', str(path)], capture_output=True, text=True).stdout.strip()\n    try:\n        float(out); return True\n    except ValueError:\n        return False","tryCatchPattern":"from agent_reach.transcribe import TranscribeError\ntry:\n    transcribe_audio(path)\nexcept TranscribeError as e:\n    if 'parse a valid audio duration' in str(e):\n        transcribe_audio(remux_to_m4a(path))\n    else:\n        raise","preventionTips":["Re-mux stream-ripped or raw recordings into m4a/mp4 before transcription","Pre-check duration parses with your own ffprobe call","Avoid media piped through stdin"],"tags":["ffprobe","duration","media","parsing"],"backgroundTag":null,"analyzedSha":"93ae1d18c37b707dec053c7c4f9d91cd8ef8943d","analyzedAt":"2026-08-14T22:54:06.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}