santifer/career-ops · error

beesite: cannot resolve search host for

Error message

beesite: cannot resolve search host for ${entry.name}

What it means

The beesite provider's fetch() calls resolveConfig(entry) to determine the search host (beesite instances are per-customer deployments). When it returns null — no usable api/search URL on a recognized beesite origin — the provider throws and skips nothing silently.

Solutions

  1. Add the entry's explicit `api:` (search endpoint) URL for its beesite instance — resolveConfig accepts a url-shaped api value.
  2. Open the company's job board and copy the actual search request URL (DevTools network tab) into the config.
  3. If the beesite deployment moved, update the host in the entry to the new origin.
  4. Pre-validate: run resolveConfig across all beesite entries at startup and report unresolvable ones before scanning.

Example fix

// before
{ name: 'ExampleOrg', careers_url: 'https://exampleco.jobs' }
// fetch throws: cannot resolve search host

// after
{ name: 'ExampleOrg', api: 'https://exampleco.beesite.com/search?query=' }
Defensive patterns

Strategy: fallback

Validate before calling

function hasBeesiteHost(entry) {
  return resolveConfig(entry) != null;
}

Type guard

function isBeesiteReadyEntry(entry) {
  const cfg = entry ? resolveConfig(entry) : null;
  return cfg != null && typeof cfg.searchUrl === 'string' && cfg.searchUrl.startsWith('https://');
}

Try / catch

try {
  return await beesiteProvider.fetch(entry, ctx);
} catch (err) {
  if (/cannot resolve search host/.test(err.message)) {
    console.warn(`Entry ${entry.name}: no recognizable beesite search endpoint — check portals.yml`);
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling fetch(entry) with an entry lacking an `api` URL (or a url that resolveConfig can't map) — e.g. only a corporate careers page or an endpoint on a domain resolveConfig doesn't recognize as a beesite host.

Common situations: portals.yml entry for a public-sector/beesite-hosted board where the actual search endpoint URL was never captured; the customer's beesite host changed; entry copied from a provider with a different config shape.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


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

Appendix: source

Thrown at providers/beesite.mjs:153

function resolveMaxPages(entry) {
  const v = entry?.max_pages;
  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES);
  return MAX_PAGES;
}

/** @type {Provider} */
export default {
  id: 'beesite',

  detect(entry) {
    const url = entry.api || entry.careers_url || '';
    if (typeof url !== 'string') return null;
    return resolveConfig({ api: url }) ? { url } : null;
  },

  async fetch(entry, ctx) {
    const cfg = resolveConfig(entry);
    if (!cfg) throw new Error(`beesite: cannot resolve search host for ${entry.name}`);

    const wait = (ms) => (ctx.sleep ? ctx.sleep(ms) : new Promise((r) => setTimeout(r, ms)));
    const maxPages = resolveMaxPages(entry);
    const jobs = [];
    const seen = new Set();
    let total = null;

    for (let page = 0; page < maxPages; page++) {
      if (page > 0) await wait(PAGE_DELAY_MS);
      const json = await ctx.fetchJson(buildSearchUrl(cfg, page * PAGE_SIZE + 1), {
        redirect: 'error',
        headers: { accept: 'application/json' },
      });
      const { total: pageTotal, rows } = parseSearchResult(json);
      if (total === null) total = pageTotal;
      if (rows.length === 0) break; // past the last page

      let fresh = 0;

View on GitHub (pinned to aac998c7ed)