{"record":{"id":"3c0f24fbfdba3623","repo":"Panniantong/Agent-Reach","slug":"ffprobe-could-not-parse-a-valid-positive-audio-dur","errorCode":null,"errorMessage":"ffprobe could not parse a valid positive audio duration","messagePattern":"ffprobe could not parse a valid positive audio duration","errorType":"exception","errorClass":"TranscribeError","httpStatus":null,"severity":"error","filePath":"agent_reach/transcribe.py","lineNumber":138,"sourceCode":"        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\n\n\ndef _run(cmd: List[str], timeout: int = 600) -> None:\n    \"\"\"Run a subprocess, raising TranscribeError on nonzero exit or timeout.","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/Panniantong/Agent-Reach/blob/93ae1d18c37b707dec053c7c4f9d91cd8ef8943d/agent_reach/transcribe.py#L120-L156","documentation":"Raised by _probe_audio_duration() in agent_reach/transcribe.py when ffprobe returns a parseable duration that is non-finite (NaN/inf), zero, or negative. The pipeline computes a chunk budget from the duration, so a non-positive value would break chunking arithmetic and is rejected before media generation proceeds.","triggerScenarios":"ffprobe emitting 0 for an empty/zero-byte-ish file, or inf/NaN for malformed containers with unbounded stream length.","commonSituations":"Empty files created by a failed download or recorder crash; truncated files whose headers claim a stream but contain no samples.","solutions":["Check the file actually contains audio (play it or check size) — an empty recording yields duration 0","Re-record or re-download the source; a file that reports 0 s has no content to transcribe","Filter zero-length files upstream before calling transcribe"],"exampleFix":"# before\nfiles = list(dir.glob('*.m4a'))\nfor f in files: transcribe_audio(f)  # empty recording -> error\n\n# after\nfiles = [f for f in dir.glob('*.m4a') if f.stat().st_size > 1024]\nfor f in files: transcribe_audio(f)","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()\nimport math\nd = float(out) if out else 0.0\nif not math.isfinite(d) or d <= 0:\n    raise ValueError('no transcribable audio content')","typeGuard":"def has_positive_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        return math.isfinite(float(out)) and float(out) > 0\n    except ValueError:\n        return False","tryCatchPattern":"from agent_reach.transcribe import TranscribeError\ntry:\n    transcribe_audio(path)\nexcept TranscribeError as e:\n    if 'positive audio duration' in str(e):\n        path.unlink(missing_ok=True)  # empty artifact; drop and continue\n    else:\n        raise","preventionTips":["Filter zero-byte / tiny files before transcription","Confirm recordings actually captured samples (recorder exit status)","Guard chunk-budget math upstream with the same finite-and-positive check"],"tags":["ffprobe","duration","media","validation"],"backgroundTag":null,"analyzedSha":"93ae1d18c37b707dec053c7c4f9d91cd8ef8943d","analyzedAt":"2026-08-14T22:54:06.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}