{"record":{"id":"0852961160588045","repo":"can1357/oh-my-pi","slug":"failed-to-fetch-new-stories","errorCode":null,"errorMessage":"Failed to fetch new stories","messagePattern":"Failed to fetch new stories","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/web/scrapers/hackernews.ts","lineNumber":162,"sourceCode":"\ttry {\n\t\tconst itemId = parsed.searchParams.get(\"id\");\n\n\t\tif (itemId) {\n\t\t\tconst item = await fetchItem(parseInt(itemId, 10), timeout, signal);\n\t\t\tif (!item) throw new Error(`Failed to fetch item ${itemId}`);\n\n\t\t\tcontent = await renderStory(item, timeout, 0, signal);\n\t\t\tnotes.push(`Fetched HN item ${itemId} with top-level comments (depth 2)`);\n\t\t} else if (parsed.pathname === \"/\" || parsed.pathname === \"/news\") {\n\t\t\tconst { content: raw, ok } = await loadPage(`${API_BASE}/topstories.json`, { timeout, signal });\n\t\t\tif (!ok) throw new Error(\"Failed to fetch top stories\");\n\t\t\tconst ids = tryParseJson<number[]>(raw);\n\t\t\tif (!ids) throw new Error(\"Failed to parse top stories\");\n\t\t\tcontent = await renderListing(ids, timeout, \"Hacker News - Top Stories\", signal);\n\t\t\tnotes.push(\"Fetched top 20 stories from HN front page\");\n\t\t} else if (parsed.pathname === \"/newest\") {\n\t\t\tconst { content: raw, ok } = await loadPage(`${API_BASE}/newstories.json`, { timeout, signal });\n\t\t\tif (!ok) throw new Error(\"Failed to fetch new stories\");\n\t\t\tconst ids = tryParseJson<number[]>(raw);\n\t\t\tif (!ids) throw new Error(\"Failed to parse new stories\");\n\t\t\tcontent = await renderListing(ids, timeout, \"Hacker News - New Stories\", signal);\n\t\t\tnotes.push(\"Fetched top 20 new stories\");\n\t\t} else if (parsed.pathname === \"/best\") {\n\t\t\tconst { content: raw, ok } = await loadPage(`${API_BASE}/beststories.json`, { timeout, signal });\n\t\t\tif (!ok) throw new Error(\"Failed to fetch best stories\");\n\t\t\tconst ids = tryParseJson<number[]>(raw);\n\t\t\tif (!ids) throw new Error(\"Failed to parse best stories\");\n\t\t\tcontent = await renderListing(ids, timeout, \"Hacker News - Best Stories\", signal);\n\t\t\tnotes.push(\"Fetched top 20 best stories\");\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn buildResult(content, { url, method: \"hackernews\", fetchedAt, notes });\n\t} catch (err) {\n\t\tconst errorMsg = err instanceof Error ? err.message : String(err);","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/scrapers/hackernews.ts#L144-L180","documentation":"Thrown by handleHackerNews when `loadPage` returns `ok: false` for the Firebase `newstories.json` endpoint while handling https://news.ycombinator.com/newest. Same failure semantics as the top-stories variant: transport error, non-2xx status, or unreadable body after user-agent rotation.","triggerScenarios":"Calling web-fetch on https://news.ycombinator.com/newest when GET https://hacker-news.firebaseio.com/v0/newstories.json fails (network outage, DNS failure, HTTP error, blocked user agents).","commonSituations":"Firebase API outage; offline/air-gapped environment; DNS failure; rate limiting; firewall blocking Firebase hosting; transient timeout under slow networks.","solutions":["Verify connectivity: curl -I https://hacker-news.firebaseio.com/v0/newstories.json, then retry.","Read the notes/error in the returned result block for the underlying transport error.","Use the Algolia HN API (search_by_date with tags=story) as a fallback for newest stories.","Increase the timeout if failures are timeouts.","Check proxy/firewall rules for Firebase hosting domains."],"exampleFix":"// before\nconst res = await webFetch(\"https://news.ycombinator.com/newest\");\n// after: pre-check upstream health and degrade\nconst health = await fetch(\"https://hacker-news.firebaseio.com/v0/newstories.json\", { method: \"HEAD\" });\nif (!health.ok) return algoliaNewestFallback();\nconst res = await webFetch(\"https://news.ycombinator.com/newest\");","handlingStrategy":"retry","validationCode":"const probe = await fetch(\"https://hacker-news.firebaseio.com/v0/newstories.json\", { method: \"HEAD\" });\nif (!probe.ok) throw new Error(`HN Firebase unreachable: ${probe.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  const res = await webFetch(\"https://news.ycombinator.com/newest\");\n} catch (err) {\n  if (err instanceof ToolAbortError) throw err;\n  // fall back to Algolia search_by_date\n}","preventionTips":["HEAD-probe newstories.json before fetching /newest.","Retry once with backoff; Firebase glitches are transient.","Verify DNS resolution of hacker-news.firebaseio.com in the environment.","Keep an Algolia by-date fallback.","Raise timeout on slow links instead of disabling timeouts."],"tags":["network","http","hacker-news","firebase"],"backgroundTag":"fetch-failed-non-ok-response","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}