santifer/career-ops · warning

archive render skipped — Greenhouse API unreachable

Error message

archive render skipped — Greenhouse API unreachable

What it means

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.

Solutions

  1. 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.
  2. Re-run later: Greenhouse outages are transient; the test is designed to skip, not fail.
  3. If the pinned board reliably returns nothing, point the test at a different stable Greenhouse board.
  4. Accept the skip when developing offline — no repo code is at fault.

Example fix

// before
const res = await fetch('https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false');
// after
const res = await fetch(process.env.ARCHIVE_TEST_BOARD_URL || 'https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false');
Defensive patterns

Strategy: retry

Validate before calling

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');

Type guard

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; } };

Try / catch

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'); }

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


AI-assisted analysis of santifer/career-ops@e7abd431fc (2026-09-16). Data as JSON: /api/errors/2c3fd065c2386a33. Report an issue: GitHub.

Appendix: source

Thrown at test-all.mjs:7137

} catch { /* playwright not installed */ }

if (!hasBrowser) {
  warn('archive render skipped — no Playwright browser in env');
} else {
  let liveJobUrl = null;
  try {
    const res = await fetch('https://boards-api.greenhouse.io/v1/boards/anthropic/jobs?content=false');
    const { jobs } = await res.json();
    const candidate = jobs?.[0]?.absolute_url ?? null;
    if (candidate) {
      const u = new URL(candidate);
      const allowed = new Set(['boards.greenhouse.io', 'job-boards.greenhouse.io']);
      if (u.protocol === 'https:' && allowed.has(u.hostname)) liveJobUrl = candidate;
    }
  } catch { /* offline — degrade gracefully */ }

  if (!liveJobUrl) {
    warn('archive render skipped — Greenhouse API unreachable');
  } else {
    const JDS_DIR = join(ROOT, 'jds');
    const startedAt = Date.now();
    const archiveOut = run('node', ['archive-posting.mjs', liveJobUrl], { timeout: 60000 });

    if (archiveOut === null) {
      fail('live archive: script exited non-zero on live URL');
    } else {
      pass('live archive: exited 0');

      const recent = existsSync(JDS_DIR)
        ? readdirSync(JDS_DIR)
            .filter(f => f.endsWith('.pdf'))
            .filter(f => statSync(join(JDS_DIR, f)).mtimeMs >= startedAt)
        : [];

      if (recent.length === 0) {
        fail('live archive: no PDF written to jds/ during test run');

View on GitHub (pinned to e7abd431fc)