{"record":{"id":"2c3fd065c2386a33","repo":"santifer/career-ops","slug":"archive-render-skipped-greenhouse-api-unreachable","errorCode":null,"errorMessage":"archive render skipped — Greenhouse API unreachable","messagePattern":"archive render skipped — Greenhouse API unreachable","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"test-all.mjs","lineNumber":7137,"sourceCode":"} catch { /* playwright not installed */ }\n\nif (!hasBrowser) {\n  warn('archive render skipped — no Playwright browser in env');\n} else {\n  let liveJobUrl = null;\n  try {\n    const res = await fetch('https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false');\n    const { jobs } = await res.json();\n    const candidate = jobs?.[0]?.absolute_url ?? null;\n    if (candidate) {\n      const u = new URL(candidate);\n      const allowed = new Set(['boards.greenhouse.io', 'job-boards.greenhouse.io']);\n      if (u.protocol === 'https:' && allowed.has(u.hostname)) liveJobUrl = candidate;\n    }\n  } catch { /* offline — degrade gracefully */ }\n\n  if (!liveJobUrl) {\n    warn('archive render skipped — Greenhouse API unreachable');\n  } else {\n    const JDS_DIR = join(ROOT, 'jds');\n    const startedAt = Date.now();\n    const archiveOut = run('node', ['archive-posting.mjs', liveJobUrl], { timeout: 60000 });\n\n    if (archiveOut === null) {\n      fail('live archive: script exited non-zero on live URL');\n    } else {\n      pass('live archive: exited 0');\n\n      const recent = existsSync(JDS_DIR)\n        ? readdirSync(JDS_DIR)\n            .filter(f => f.endsWith('.pdf'))\n            .filter(f => statSync(join(JDS_DIR, f)).mtimeMs >= startedAt)\n        : [];\n\n      if (recent.length === 0) {\n        fail('live archive: no PDF written to jds/ during test run');","sourceCodeStart":7119,"sourceCodeEnd":7155,"githubUrl":"https://github.com/santifer/career-ops/blob/e7abd431fce9348a95261acac9e0c14779c35df8/test-all.mjs#L7119-L7155","documentation":"The archive-render test needs a live job URL to exercise archive-posting.mjs; it fetches the public Greenhouse board API for a known board. If the fetch fails, returns no usable job URL, or the URL's host is not in the allowed greenhouse host set, the test warns and skips rendering instead of failing on a network condition.","triggerScenarios":"`fetch('https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false')` throws (offline, DNS failure, proxy), or the response contains no jobs[0].absolute_url, or the candidate URL's hostname is not boards.greenhouse.io / job-boards.greenhouse.io.","commonSituations":"Running the suite offline or behind a corporate proxy blocking external APIs, Greenhouse API rate limiting or the board being emptied, or the known board changing so no candidates are returned.","solutions":["Verify network access: `curl https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false` — if it fails, fix connectivity/proxy (set HTTPS_PROXY) and rerun.","Re-run later: Greenhouse outages are transient; the test is designed to skip, not fail.","If the pinned board reliably returns nothing, point the test at a different stable Greenhouse board.","Accept the skip when developing offline — no repo code is at fault."],"exampleFix":"// before\nconst res = await fetch('https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false');\n// after\nconst res = await fetch(process.env.ARCHIVE_TEST_BOARD_URL || 'https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false');","handlingStrategy":"retry","validationCode":"let reachable = false; try { const r = await fetch('https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false'); reachable = r.ok; } catch {} if (!reachable) console.warn('Greenhouse unreachable; archive render test will skip');","typeGuard":"const isAllowedJobUrl = (u) => { try { const p = new URL(u); return p.protocol === 'https:' && ['boards.greenhouse.io','job-boards.greenhouse.io'].includes(p.hostname); } catch { return false; } };","tryCatchPattern":"try { const res = await fetch(boardUrl); const { jobs } = await res.json(); liveJobUrl = jobs?.[0]?.absolute_url ?? null; } catch { warn('archive render skipped — Greenhouse API unreachable'); }","preventionTips":["Configure proxy env vars (HTTPS_PROXY) when behind a corporate firewall","Treat external-API-dependent tests as skippable-by-design and retry in CI","Pin an alternate fallback board in case the known board empties","Check the API manually with curl when the warning repeats"],"tags":["network","greenhouse","api","offline"],"backgroundTag":"network-request-failed","analyzedSha":"e7abd431fce9348a95261acac9e0c14779c35df8","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}