Panniantong/Agent-Reach · error · RuntimeError
curl could not complete the V2EX TLS fallback
Error message
curl could not complete the V2EX TLS fallback
What it means
Raised by _get_json_with_curl (agent_reach/channels/v2ex.py:120) when launching curl itself fails: subprocess.run raised OSError (exec format error, permission denied) or curl exceeded its hard timeout (_TIMEOUT + 2 = 12 seconds) and was killed via TimeoutExpired. The original exception is chained with `from exc`.
Source
Thrown at agent_reach/channels/v2ex.py:120
str(_TIMEOUT),
"--max-filesize",
str(_MAX_RESPONSE_BYTES),
"--header",
f"User-Agent: {_UA}",
"--url",
url,
]
try:
result = subprocess.run(
command,
capture_output=True,
encoding="utf-8",
errors="replace",
timeout=_TIMEOUT + 2,
env=utf8_subprocess_env(),
)
except (OSError, subprocess.TimeoutExpired) as exc:
raise RuntimeError("curl could not complete the V2EX TLS fallback") from exc
if result.returncode != 0:
raise RuntimeError("curl could not complete the V2EX TLS fallback")
if len(result.stdout.encode("utf-8")) > _MAX_RESPONSE_BYTES:
raise ValueError("V2EX API response exceeds the 1 MiB safety limit")
return json.loads(result.stdout)
def _get_json(url: str) -> Any:
"""Fetch JSON, retrying only Python's known TLS EOF via native curl."""
try:
return _get_json_with_urllib(url)
except Exception as exc:
if isinstance(exc, ssl.SSLCertVerificationError):
raise
if not _is_unexpected_tls_eof(exc):
raise
return _get_json_with_curl(url)
View on GitHub (pinned to 93ae1d18c3)
Solutions
- Run `curl -v --max-time 10 https://www.v2ex.com/api/topics/hot.json` manually to see if curl completes at all
- If curl hangs, fix the network path (proxy, DNS, firewall) to www.v2ex.com:443
- If OSError is exec-related, check `ls -l $(which curl)` for execute permission and that the binary matches the architecture
- Retry with backoff in the caller — this error is often transient (timeout-class)
Example fix
# caller-side retry for the V2EX channel
import time
from agent_reach.channels.v2ex import V2EXChannel
ch = V2EXChannel()
for attempt in range(3):
try:
data = ch.read("https://www.v2ex.com/api/topics/hot.json")
break
except RuntimeError:
if attempt == 2:
raise
time.sleep(2 ** attempt) Defensive patterns
Strategy: retry
Try / catch
from agent_reach.channels.v2ex import V2EXChannel
last = None
for attempt in range(3):
try:
result = V2EXChannel().read(url)
break
except RuntimeError as exc:
# both curl-launch OSError and TimeoutExpired surface here
last = exc
if last is not None and 'result' not in dir():
raise last Prevention
- Keep V2EX reads under a per-run budget so one hung curl (12s subprocess timeout) cannot stall the agent
- Verify outbound connectivity to www.v2ex.com:443 in your deployment health checks
- Retry with exponential backoff; timeout-class failures are frequently transient
When it happens
Trigger: V2EX read/search where urllib hit TLS EOF, curl exists, but: the curl binary is not executable, the OS cannot fork (resource limits), or curl hangs past 12s (blackholed network, DNS stall) and subprocess.run raises TimeoutExpired.
Common situations: Containers with PID limits or no exec permission on the curl binary; firewalled networks where TCP connections to v2ex.com:443 silently drop so curl never completes; heavily loaded hosts where fork() fails.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- curl is unavailable for the V2EX TLS fallback
- {cmd[0]} timed out after {timeout}s
- invalid V2EX API URL
- only the V2EX HTTPS API is allowed
- V2EX API response exceeds the 1 MiB safety limit
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/06f0ef1b81a00ad7.
Report an issue: GitHub.