santifer/career-ops · error · Error

vc-portfolios: a16z portfolio fetch failed

Error message

vc-portfolios: a16z portfolio fetch failed — ${err.message}

What it means

fetchA16zCompanies downloads the a16z portfolio HTML page via fetchWithTimeout and re-throws any fetch failure as 'vc-portfolios: a16z portfolio fetch failed — <cause>'. Unlike the YC fetcher, there is no partial-data fallback: any network or HTTP error is fatal for this source. Parsing failures (parseA16zPayload) are NOT caught here — only the fetch itself.

Solutions

  1. Test A16Z_PORTFOLIO_URL with curl -I to see the actual status; if 403/Cloudflare, the endpoint needs a browser-like User-Agent or a headless-browser fetch
  2. Verify the portfolio page still exists after a site redesign and update A16Z_PORTFOLIO_URL to the new URL
  3. Increase timeoutMs if the failure is a timeout on a slow connection
  4. Check the inner err.message — timeouts, DNS failures (ENOTFOUND) and HTTP statuses each need different fixes (network/VPN vs URL update vs backoff)

Example fix

// before
const res = await fetchWithTimeout(A16Z_PORTFOLIO_URL, { timeoutMs });
// Error: vc-portfolios: a16z portfolio fetch failed — HTTP 403: ...Just a moment...
// after: allow configuring a browser-like UA / longer timeout
const res = await fetchWithTimeout(A16Z_PORTFOLIO_URL, { timeoutMs: 30000, headers: { 'user-agent': 'Mozilla/5.0 (compatible; seed-fetcher)' } });
Defensive patterns

Strategy: fallback

Validate before calling

const status = await fetch(A16Z_PORTFOLIO_URL, { method: 'HEAD' })
  .then(r => r.status).catch(() => 0);
if (status !== 200) console.warn(`a16z portfolio URL unhealthy (HTTP ${status}) — expect fetch failure`);

Try / catch

let companies;
try {
  companies = await fetchA16zCompanies({ timeoutMs });
} catch (err) {
  console.warn(`${err.message}; using cached a16z portfolio`);
  companies = loadCachedA16z() ?? [];
}

Prevention

When it happens

Trigger: Calling fetchA16zCompanies when https://a16z.com/portfolio (A16Z_PORTFOLIO_URL) returns a non-2xx status via fetchWithTimeout (403 from bot protection, 404 after a site redesign, 5xx outage), or the request times out / DNS fails.

Common situations: a16z.com serving a Cloudflare challenge page to non-browser clients (403); the portfolio URL changed when a16z redesigned their site; corporate firewall blocks the domain; timeout hit because the page is large and the connection is slow.

Related errors


AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/48361f7727fd0b05. Report an issue: GitHub.

Appendix: source

Thrown at seeds/vc-portfolios.mjs:419

  return null;
}

/**
 * Fetch the a16z public portfolio page and return parsed SeedCompany entries.
 *
 * a16z does not expose a public JSON API, so we fetch the HTML portfolio page
 * and parse it with `parseA16zPayload()`.
 *
 * @param {{ timeoutMs?: number }} [opts]
 * @returns {Promise<SeedCompany[]>}
 */
export async function fetchA16zCompanies({ timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
  let html;
  try {
    const res = await fetchWithTimeout(A16Z_PORTFOLIO_URL, { timeoutMs });
    html = await res.text();
  } catch (err) {
    throw new Error(`vc-portfolios: a16z portfolio fetch failed — ${err.message}`);
  }
  return parseA16zPayload(html);
}

// ── SEED_SOURCES registry ────────────────────────────────────────────

/**
 * Registry mapping seed source names to their fetch functions.
 * Consumed by scan-ats-full.mjs --seeds flag and CLI tooling.
 *
 * To add a new VC portfolio:
 *  1. Add a fetchXyzCompanies() function above.
 *  2. Add an entry here: { fetch: fetchXyzCompanies, label: 'XYZ Portfolio' }
 *
 * @type {Record<string, { fetch: (opts?: object) => Promise<SeedCompany[]>, label: string }>}
 */
export const SEED_SOURCES = {
  yc: {

View on GitHub (pinned to 1696bec4d0)