can1357/oh-my-pi · error
Failed to fetch top stories
Error message
Failed to fetch top stories
What it means
Thrown by handleHackerNews when `loadPage` returns `ok: false` for the Firebase `topstories.json` endpoint while handling the HN front page (`/` or `/news`). loadPage reports ok:false on transport errors, non-2xx status, or when the response has no readable body after trying its user-agent rotation (curl, TextBot, Chrome UA).
Source
Thrown at packages/coding-agent/src/web/scrapers/hackernews.ts:155
const parsed = new URL(url);
if (!parsed.hostname.includes("news.ycombinator.com")) return null;
const notes: string[] = [];
let content = "";
const fetchedAt = new Date().toISOString();
try {
const itemId = parsed.searchParams.get("id");
if (itemId) {
const item = await fetchItem(parseInt(itemId, 10), timeout, signal);
if (!item) throw new Error(`Failed to fetch item ${itemId}`);
content = await renderStory(item, timeout, 0, signal);
notes.push(`Fetched HN item ${itemId} with top-level comments (depth 2)`);
} else if (parsed.pathname === "/" || parsed.pathname === "/news") {
const { content: raw, ok } = await loadPage(`${API_BASE}/topstories.json`, { timeout, signal });
if (!ok) throw new Error("Failed to fetch top stories");
const ids = tryParseJson<number[]>(raw);
if (!ids) throw new Error("Failed to parse top stories");
content = await renderListing(ids, timeout, "Hacker News - Top Stories", signal);
notes.push("Fetched top 20 stories from HN front page");
} else if (parsed.pathname === "/newest") {
const { content: raw, ok } = await loadPage(`${API_BASE}/newstories.json`, { timeout, signal });
if (!ok) throw new Error("Failed to fetch new stories");
const ids = tryParseJson<number[]>(raw);
if (!ids) throw new Error("Failed to parse new stories");
content = await renderListing(ids, timeout, "Hacker News - New Stories", signal);
notes.push("Fetched top 20 new stories");
} else if (parsed.pathname === "/best") {
const { content: raw, ok } = await loadPage(`${API_BASE}/beststories.json`, { timeout, signal });
if (!ok) throw new Error("Failed to fetch best stories");
const ids = tryParseJson<number[]>(raw);
if (!ids) throw new Error("Failed to parse best stories");
content = await renderListing(ids, timeout, "Hacker News - Best Stories", signal);
notes.push("Fetched top 20 best stories");View on GitHub (pinned to 9690622007)
Solutions
- Confirm the machine can reach hacker-news.firebaseio.com (curl -I https://hacker-news.firebaseio.com/v0/topstories.json) and retry.
- Check the result block's notes/error for the loadPage transport error detail to identify DNS vs HTTP vs timeout.
- If Firebase is unavailable, fall back to the Algolia HN API (https://hn.algolia.com/api/v1/search?tags=front_page).
- Increase the tool timeout if requests were timing out.
- Check for proxy/firewall rules blocking requests to Google Firebase hosting domains.
Example fix
// before: blind retry loop
for (let i = 0; i < 5; i++) await webFetch("https://news.ycombinator.com/");
// after: probe the upstream API first, then degrade gracefully
const probe = await fetch("https://hacker-news.firebaseio.com/v0/topstories.json");
if (!probe.ok) {
const alt = await fetch("https://hn.algolia.com/api/v1/search?tags=front_page");
// use Algolia results instead
} Defensive patterns
Strategy: retry
Validate before calling
const probe = await fetch("https://hacker-news.firebaseio.com/v0/topstories.json", { method: "HEAD" });
if (!probe.ok) throw new Error(`HN Firebase unreachable: ${probe.status}`); Try / catch
try {
const res = await webFetch("https://news.ycombinator.com/");
} catch (err) {
if (err instanceof ToolAbortError) throw err;
const alt = await fetch("https://hn.algolia.com/api/v1/search?tags=front_page");
// degrade to Algolia listing
} Prevention
- HEAD-probe the Firebase endpoint before rendering the front page.
- Cache the story-id list briefly to reduce redundant upstream calls.
- Check connectivity/DNS in sandboxed environments before web-fetch calls.
- Keep an Algolia API fallback wired in.
- Watch for Firebase 429s and back off rather than hammering.
When it happens
Trigger: Calling web-fetch on https://news.ycombinator.com/ or /news when the GET to https://hacker-news.firebaseio.com/v0/topstories.json fails: network outage, DNS failure, Firebase 4xx/5xx, or all three user-agent attempts blocked.
Common situations: HN Firebase API outage or maintenance; sandboxed/air-gapped environment without internet; DNS resolution failure for hacker-news.firebaseio.com; rate limiting by Google's Firebase hosting; IPv6-only breakage.
Related errors
- Failed to fetch new stories
- Failed to fetch best stories
- Failed to fetch item ${itemId}
- V2 remote compaction failed (${response.status} ${response.s
- sso-role
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a724dcbb4f12ba3d.
Report an issue: GitHub.