can1357/oh-my-pi · error

Failed to fetch best stories

Error message

Failed to fetch best stories

What it means

Thrown by handleHackerNews when `loadPage` returns `ok: false` for the Firebase `beststories.json` endpoint while handling https://news.ycombinator.com/best. Identical mechanism to the other listing endpoints: transport failure, non-2xx status, or unreadable body after the user-agent rotation in loadPage.

Source

Thrown at packages/coding-agent/src/web/scrapers/hackernews.ts:169

			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");
		} else {
			return null;
		}

		return buildResult(content, { url, method: "hackernews", fetchedAt, notes });
	} catch (err) {
		const errorMsg = err instanceof Error ? err.message : String(err);
		notes.push(`Error: ${errorMsg}`);
		return buildResult(`# Error fetching Hacker News content\n\n${errorMsg}`, {
			url,
			method: "hackernews",
			fetchedAt,
			notes,
		});

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify connectivity to hacker-news.firebaseio.com and retry.
  2. Inspect the notes/error in the returned result block for the underlying transport error.
  3. Use Algolia HN API as a best-stories fallback.
  4. Increase the timeout for slow networks.
  5. Check proxy/firewall rules for Firebase hosting domains.

Example fix

// before
const res = await webFetch("https://news.ycombinator.com/best");
// after
const health = await fetch("https://hacker-news.firebaseio.com/v0/beststories.json", { method: "HEAD" });
if (!health.ok) return algoliaBestFallback();
const res = await webFetch("https://news.ycombinator.com/best");
Defensive patterns

Strategy: retry

Validate before calling

const probe = await fetch("https://hacker-news.firebaseio.com/v0/beststories.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/best");
} catch (err) {
  if (err instanceof ToolAbortError) throw err;
  // fall back to an Algolia best/top query
}

Prevention

When it happens

Trigger: Calling web-fetch on https://news.ycombinator.com/best when GET https://hacker-news.firebaseio.com/v0/beststories.json fails — network outage, DNS failure, Firebase error, blocked user agents, or timeout.

Common situations: Firebase API outage; offline environment; DNS failure; rate limiting; firewall blocking Firebase; slow network exceeding timeout.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/c190206c3b12e685. Report an issue: GitHub.