mvanhorn/last30days-skill · error · RuntimeError
Gemini request failed: {exc}
Error message
Gemini request failed: {exc} What it means
The URLError branch of call_gemini_judge(): the request never got an HTTP response — DNS failure, connection refused, TLS error, or the 120-second timeout expiring (socket.timeout is wrapped in URLError). RuntimeError preserves the original exception as __cause__.
Source
Thrown at skills/last30days/scripts/evaluate_search_quality.py:233
def call_gemini_judge(api_key: str, model: str, prompt: str) -> dict[str, Any]:
body = {
"contents": [{"parts": [{"text": prompt}]}],
"generationConfig": {"temperature": 0, "responseMimeType": "application/json"},
}
request = Request(
GEMINI_API_URL.format(model=model, api_key=api_key),
data=json.dumps(body).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urlopen(request, timeout=120) as response:
payload = json.loads(response.read().decode("utf-8"))
except HTTPError as exc:
detail = exc.read().decode("utf-8", errors="replace")
raise RuntimeError(f"Gemini HTTP {exc.code}: {detail}") from exc
except URLError as exc:
raise RuntimeError(f"Gemini request failed: {exc}") from exc
return json.loads(extract_gemini_text(payload))
def build_judge_prompt(topic: str, query_type: str, items: list[dict[str, Any]]) -> str:
item_lines = []
for item in items:
item_lines.append(
"\n".join([
f"- id: {item['key']}",
f" source: {item['source']}",
f" title: {item['text'][:220]}",
f" url: {item['url']}",
f" date: {item.get('date') or 'unknown'}",
])
)
return f"""
Judge search-result relevance for a last-30-days research tool.
View on GitHub (pinned to c7460f6114)
Solutions
- Check basic connectivity: curl -sS https://generativelanguage.googleapis.com from the same environment.
- Unset or fix HTTP_PROXY/HTTPS_PROXY/ALL_PROXY if a stale proxy is configured.
- If timeouts (reason contains 'timed out'), reduce the number of items passed to build_judge_prompt or raise the timeout in urlopen.
- Retry with backoff for transient DNS/socket errors before giving up.
Example fix
# before with urlopen(request, timeout=120) as response: # after with urlopen(request, timeout=300) as response:
Defensive patterns
Strategy: retry
Validate before calling
import socket
socket.create_connection(('generativelanguage.googleapis.com', 443), timeout=10) # preflight Try / catch
try:
return call_gemini_judge(api_key, model, prompt)
except RuntimeError as exc:
if 'request failed' not in str(exc):
raise
# network-level failure: backoff once, then report connectivity problem
time.sleep(5)
return call_gemini_judge(api_key, model, prompt) Prevention
- Preflight connectivity in CI/sandboxed environments before launching evaluation batches.
- Keep judge prompts small enough that generation finishes well under the 120s timeout.
- Pin correct HTTP(S)_PROXY settings or disable stale proxies in cron environments.
When it happens
Trigger: urlopen(request, timeout=120) raising URLError: no route to generativelanguage.googleapis.com (offline sandbox/CI), proxy or corporate firewall blocking the host, DNS resolution failure, or generation exceeding the 120s timeout (socket timeout surfaces as URLError reason).
Common situations: CI runners without network egress; local proxy env vars (HTTP_PROXY/HTTPS_PROXY) pointing at a dead proxy; IPv6-only misrouting; very large judge prompts making the model exceed 120s.
Related errors
- {exc}
- Gemini response did not contain text.
- Gemini HTTP {exc.code}: {detail}
- {status}: {message}
- {exc.reason}
AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15).
Data as JSON: /api/errors/12f403392e5f243e.
Report an issue: GitHub.