{"record":{"id":"f757874a6eff9c0c","repo":"santifer/career-ops","slug":"vc-portfolios-yc-api-fetch-failed-err-message","errorCode":null,"errorMessage":"vc-portfolios: YC API fetch failed — ${err.message}","messagePattern":"vc-portfolios: YC API fetch failed — (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"seeds/vc-portfolios.mjs","lineNumber":347,"sourceCode":" */\nexport async function fetchYCCompanies({ timeoutMs = DEFAULT_TIMEOUT_MS, maxPages = YC_MAX_PAGES } = {}) {\n  /** @type {SeedCompany[]} */\n  const all = [];\n  const seen = new Set();\n\n  // YC_MAX_PAGES is a hard ceiling: clamp here so an explicit maxPages (or a\n  // stray Infinity) can never spin the walk past the runaway guard.\n  const limit = Math.min(maxPages, YC_MAX_PAGES);\n\n  let page = 1;\n  for (let fetched = 0; fetched < limit; fetched++) {\n    const url = `https://api.ycombinator.com/v0.1/companies?page=${page}&per_page=1000`;\n    let payload;\n    try {\n      const res = await fetchWithTimeout(url, { timeoutMs });\n      payload = await res.json();\n    } catch (err) {\n      if (page === 1) throw new Error(`vc-portfolios: YC API fetch failed — ${err.message}`);\n      break; // Partial data is fine after page 1.\n    }\n\n    const entries = parseYCPayload(payload);\n    if (entries.length === 0) break; // No more companies.\n\n    for (const e of entries) {\n      if (!seen.has(e.slug)) {\n        seen.add(e.slug);\n        all.push(e);\n      }\n    }\n\n    // The API caps page size server-side (~30/page; per_page is ignored) and\n    // reports totalPages — follow its signal instead of guessing from batch size.\n    const raw = /** @type {any} */ (payload);\n    if (Number.isInteger(raw?.totalPages) && raw.totalPages > 0) {\n      if (page >= raw.totalPages) break;","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/santifer/career-ops/blob/1696bec4d021768e7359f9aad6b329cba883da20/seeds/vc-portfolios.mjs#L329-L365","documentation":"fetchYCCompanies paginates the YC companies API (api.ycombinator.com/v0.1/companies). If the very first page (page === 1) fetch fails — whether from fetchWithTimeout throwing an HTTP error or res.json() failing to parse — the function aborts with 'vc-portfolios: YC API fetch failed — <cause>'. Failures on pages after the first are tolerated and return partial data, so this error specifically means the seed builder could not retrieve ANY YC data.","triggerScenarios":"Calling fetchYCCompanies when page 1 of https://api.ycombinator.com/v0.1/companies returns a non-2xx status (rate limited, API down) or returns a body that is not valid JSON (HTML error page, empty body), causing fetchWithTimeout or res.json() to throw.","commonSituations":"YC API outage or deprecation of the v0.1 endpoint; rate limiting after repeated seed runs; a captive portal / proxy returning an HTML page so res.json() throws SyntaxError; DNS/network failure in a CI job without internet access.","solutions":["Check the inner err.message for the root cause (HTTP status vs JSON parse error) and test the URL directly with curl","Wait and retry if rate-limited (429) or if the YC API is having an incident","Verify network access from the environment running the seed script (CI containers often lack egress)","If the v0.1 API is deprecated, update the script to the current YC API version or a YC company dataset export"],"exampleFix":"// before\nnode seeds/vc-portfolios.mjs\n// Error: vc-portfolios: YC API fetch failed — HTTP 429: Too Many Requests\n// after: add retry/backoff around the first page\ncurl -s -o /dev/null -w '%{http_code}' 'https://api.ycombinator.com/v0.1/companies?page=1&per_page=1000'\n// if 429, wait (e.g. sleep 60) or reduce request frequency, then rerun","handlingStrategy":"retry","validationCode":"const reachable = await fetch('https://api.ycombinator.com/v0.1/companies?page=1&per_page=1')\n  .then(r => r.ok).catch(() => false);\nif (!reachable) { /* abort or defer the YC seed step */ }","typeGuard":null,"tryCatchPattern":"try {\n  const companies = await fetchYCCompanies({ timeoutMs });\n} catch (err) {\n  console.error(`YC seed unavailable: ${err.message}`);\n  // retry later or continue with other seed sources\n}","preventionTips":["Add exponential backoff on the first-page fetch before failing","Cache the last successful YC payload and fall back to it on total failure","Schedule seed runs off-peak to avoid rate limits","Alert on this error in CI so an API deprecation is noticed quickly"],"tags":["http","network","api","rate-limit","yc-api"],"backgroundTag":"http-non-2xx-response","analyzedSha":"1696bec4d021768e7359f9aad6b329cba883da20","analyzedAt":"2026-09-01T19:19:23.111Z","contentChangedAt":"2026-09-01T19:19:23.111Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}