Panniantong/Agent-Reach · error · TranscribeError
{cmd[0]} timed out after {timeout}s
Error message
{cmd[0]} timed out after {timeout}s What it means
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.
Source
Thrown at agent_reach/transcribe.py:170
return duration
def _run(cmd: List[str], timeout: int = 600) -> None:
"""Run a subprocess, raising TranscribeError on nonzero exit or timeout.
cmd carries user-supplied URLs/paths into yt-dlp/ffmpeg — a stalled
network read or a hung probe must not block the CLI forever.
"""
try:
proc = subprocess.run(
cmd,
capture_output=True,
encoding="utf-8",
errors="replace",
timeout=timeout,
)
except subprocess.TimeoutExpired:
raise TranscribeError(f"{cmd[0]} timed out after {timeout}s")
if proc.returncode != 0:
raise TranscribeError(
f"{cmd[0]} failed (exit {proc.returncode}): {proc.stderr.strip()[:300]}"
)
def _literal_ip(host: str):
"""Return the address a literal host denotes, or None for a real hostname.
``ipaddress`` only accepts the canonical dotted-quad form, but the C
resolver behind yt-dlp accepts the whole ``inet_aton`` grammar: ``127.1``,
``2130706433``, ``0x7f000001`` and ``0177.0.0.1`` all reach 127.0.0.1, and
``0xA9FEA9FE`` reaches the cloud metadata endpoint. Parsing with the same
grammar keeps those shorthands from slipping past the private-address
check. This is literal parsing only — no name is resolved here.
"""
try:
return ipaddress.ip_address(host)View on GitHub (pinned to 93ae1d18c3)
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
Example fix
// before
transcribe("https://slow-host.example/episode.m4a") # yt-dlp timed out after 1800s
// after: download out-of-band, then transcribe locally
subprocess.run(["yt-dlp", "-x", "--audio-format", "m4a", "-R", "5", "-o", "ep.m4a", "URL"], check=True)
text = transcribe("ep.m4a") Defensive patterns
Strategy: retry
Try / catch
from agent_reach.transcribe import TranscribeError
import time
for attempt in range(2):
try:
text = transcribe(source)
break
except TranscribeError as e:
if "timed out" in str(e) and attempt == 0:
time.sleep(5)
continue
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- curl could not complete the V2EX TLS fallback
- {cmd[0]} failed (exit {proc.returncode}): {proc.stderr.strip
- {provider}: network error: {e}
- mcporter 返回的 JSON 无法解析
- mcporter JSON 缺少 servers 列表
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/b5e22954efd8174d.
Report an issue: GitHub.