Panniantong/Agent-Reach · error · TranscribeError

ffprobe could not parse a valid positive audio duration

Error message

ffprobe could not parse a valid positive audio duration

What it means

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.

Source

Thrown at agent_reach/transcribe.py:138

        raise TranscribeError(
            f"ffprobe could not read audio duration: {exc}"
        ) from exc

    if proc.returncode != 0:
        detail = proc.stderr.strip()[:300] or "unknown ffprobe error"
        raise TranscribeError(
            f"ffprobe failed while reading audio duration: {detail}"
        )

    raw_duration = proc.stdout.strip()
    try:
        duration = float(raw_duration)
    except (TypeError, ValueError):
        raise TranscribeError(
            "ffprobe could not parse a valid audio duration"
        ) from None
    if not math.isfinite(duration) or duration <= 0:
        raise TranscribeError(
            "ffprobe could not parse a valid positive audio duration"
        )
    return duration


def _require_duration_within_budget(path: Path) -> float:
    """Reject audio that cannot fit within the bounded chunk budget."""
    duration = _probe_audio_duration(path)
    if duration > MAX_AUDIO_SECONDS:
        max_minutes = MAX_AUDIO_SECONDS // 60
        raise TranscribeError(
            f"audio duration exceeds safety limit of {max_minutes} minutes"
        )
    return duration


def _run(cmd: List[str], timeout: int = 600) -> None:
    """Run a subprocess, raising TranscribeError on nonzero exit or timeout.

View on GitHub (pinned to 93ae1d18c3)

Solutions

  1. Check the file actually contains audio (play it or check size) — an empty recording yields duration 0
  2. Re-record or re-download the source; a file that reports 0 s has no content to transcribe
  3. Filter zero-length files upstream before calling transcribe

Example fix

# before
files = list(dir.glob('*.m4a'))
for f in files: transcribe_audio(f)  # empty recording -> error

# after
files = [f for f in dir.glob('*.m4a') if f.stat().st_size > 1024]
for f in files: transcribe_audio(f)
Defensive patterns

Strategy: validation

Validate before calling

out = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', '-i', str(path)], capture_output=True, text=True).stdout.strip()
import math
d = float(out) if out else 0.0
if not math.isfinite(d) or d <= 0:
    raise ValueError('no transcribable audio content')

Type guard

def has_positive_duration(path) -> bool:
    out = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'csv=p=0', '-i', str(path)], capture_output=True, text=True).stdout.strip()
    try:
        return math.isfinite(float(out)) and float(out) > 0
    except ValueError:
        return False

Try / catch

from agent_reach.transcribe import TranscribeError
try:
    transcribe_audio(path)
except TranscribeError as e:
    if 'positive audio duration' in str(e):
        path.unlink(missing_ok=True)  # empty artifact; drop and continue
    else:
        raise

Prevention

When it happens

Trigger: ffprobe emitting 0 for an empty/zero-byte-ish file, or inf/NaN for malformed containers with unbounded stream length.

Common situations: Empty files created by a failed download or recorder crash; truncated files whose headers claim a stream but contain no samples.

Related errors


AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14). Data as JSON: /api/errors/3c0f24fbfdba3623. Report an issue: GitHub.