{"record":{"id":"b5e22954efd8174d","repo":"Panniantong/Agent-Reach","slug":"cmd-0-timed-out-after-timeout-s","errorCode":null,"errorMessage":"{cmd[0]} timed out after {timeout}s","messagePattern":"(.+?) timed out after (.+?)s","errorType":"exception","errorClass":"TranscribeError","httpStatus":null,"severity":"error","filePath":"agent_reach/transcribe.py","lineNumber":170,"sourceCode":"    return duration\n\n\ndef _run(cmd: List[str], timeout: int = 600) -> None:\n    \"\"\"Run a subprocess, raising TranscribeError on nonzero exit or timeout.\n\n    cmd carries user-supplied URLs/paths into yt-dlp/ffmpeg — a stalled\n    network read or a hung probe must not block the CLI forever.\n    \"\"\"\n    try:\n        proc = subprocess.run(\n            cmd,\n            capture_output=True,\n            encoding=\"utf-8\",\n            errors=\"replace\",\n            timeout=timeout,\n        )\n    except subprocess.TimeoutExpired:\n        raise TranscribeError(f\"{cmd[0]} timed out after {timeout}s\")\n    if proc.returncode != 0:\n        raise TranscribeError(\n            f\"{cmd[0]} failed (exit {proc.returncode}): {proc.stderr.strip()[:300]}\"\n        )\n\n\ndef _literal_ip(host: str):\n    \"\"\"Return the address a literal host denotes, or None for a real hostname.\n\n    ``ipaddress`` only accepts the canonical dotted-quad form, but the C\n    resolver behind yt-dlp accepts the whole ``inet_aton`` grammar: ``127.1``,\n    ``2130706433``, ``0x7f000001`` and ``0177.0.0.1`` all reach 127.0.0.1, and\n    ``0xA9FEA9FE`` reaches the cloud metadata endpoint. Parsing with the same\n    grammar keeps those shorthands from slipping past the private-address\n    check. This is literal parsing only — no name is resolved here.\n    \"\"\"\n    try:\n        return ipaddress.ip_address(host)","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/Panniantong/Agent-Reach/blob/93ae1d18c37b707dec053c7c4f9d91cd8ef8943d/agent_reach/transcribe.py#L152-L188","documentation":"Raised by _run (transcribe.py:155-170) when an external subprocess (yt-dlp, ffmpeg) exceeds its timeout and subprocess.run raises TimeoutExpired. Timeouts are explicit per call site: yt-dlp downloads get 1800s, ffmpeg steps get the 600s default. The guard exists because user-supplied URLs flow into these binaries and a stalled network read must not hang the CLI forever.","triggerScenarios":"download_audio() on a very slow / throttled host (yt-dlp killed at 1800s); compress_audio() or chunk_audio() re-encoding a huge or pathological file past 600s. The process is killed by subprocess.run's timeout and TranscribeError wraps it.","commonSituations":"Slow networks, rate-limited CDN edges, geo-throttled media servers, or an overloaded machine where ffmpeg re-encode of a 512 MiB source takes >10 minutes. Also containerized environments with CPU quotas that make ffmpeg far slower than expected.","solutions":["Retry once — transient network stalls are the most common cause","For downloads: pre-download with your own yt-dlp invocation (resumable, -R retries), then pass the local file path to transcribe()","Check the machine's CPU/network: ffmpeg re-encode of a max-size source should finish well under 600s on normal hardware","If consistently hitting the 600s ffmpeg cap, split the source first so each compress/chunk call is smaller"],"exampleFix":"// before\ntranscribe(\"https://slow-host.example/episode.m4a\")  # yt-dlp timed out after 1800s\n\n// after: download out-of-band, then transcribe locally\nsubprocess.run([\"yt-dlp\", \"-x\", \"--audio-format\", \"m4a\", \"-R\", \"5\", \"-o\", \"ep.m4a\", \"URL\"], check=True)\ntext = transcribe(\"ep.m4a\")","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from agent_reach.transcribe import TranscribeError\nimport time\nfor attempt in range(2):\n    try:\n        text = transcribe(source)\n        break\n    except TranscribeError as e:\n        if \"timed out\" in str(e) and attempt == 0:\n            time.sleep(5)\n            continue\n        raise","preventionTips":["For flaky hosts, pre-download with yt-dlp -R retries and pass the local file","Keep per-call media sizes modest so ffmpeg stays well under the 600s cap","Watch machine load/CPU quota — slow ffmpeg is the usual non-network cause"],"tags":["timeout","subprocess","network","yt-dlp","ffmpeg"],"backgroundTag":null,"analyzedSha":"93ae1d18c37b707dec053c7c4f9d91cd8ef8943d","analyzedAt":"2026-08-14T22:54:06.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}