santifer/career-ops · error

avature: cannot resolve origin for

Error message

avature: cannot resolve origin for ${entry.name}

What it means

The Avature provider's fetch() calls resolveConfig(entry); when it returns null the provider cannot determine which Avature origin/instance to query, so it throws. Avature boards are self-hosted per customer, so the entry must supply enough info (an api URL or a recognizable origin) to build the search endpoint.

Solutions

  1. Add the entry's explicit `api:` URL pointing at the company's Avature endpoint (their real Avature search URL).
  2. Discover the actual Avature endpoint by inspecting network requests on the company's careers page and copy the search API URL into the config.
  3. If the company is not on Avature anymore, reassign the entry to the correct provider.
  4. Fail fast at config validation: run resolveConfig over all entries up front and report which ones cannot resolve.

Example fix

// before
{ name: 'ExampleCo', careers_url: 'https://exampleco.com/jobs' }
// fetch throws: cannot resolve origin

// after
{ name: 'ExampleCo', api: 'https://exampleco.avature.net/api/search' }
Defensive patterns

Strategy: fallback

Validate before calling

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

Type guard

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

Try / catch

try {
  return await avatureProvider.fetch(entry, ctx);
} catch (err) {
  if (/cannot resolve origin/.test(err.message)) {
    console.warn(`Entry ${entry.name}: add an explicit Avature api URL to portals.yml`);
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling fetch(entry) with an entry that has no `api` URL and no URL resolveConfig can map to an Avature origin — e.g. only a generic careers page, or an api URL on a domain resolveConfig does not recognize.

Common situations: portals.yml entry listing a company's own careers site with a note 'powered by Avature' but no API endpoint; tenant URL changed after a company migrated; config copied from another provider type.

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@e7abd431fc (2026-09-16). Data as JSON: /api/errors/d6e36be653224ac1. Report an issue: GitHub.

Appendix: source

Thrown at providers/avature.mjs:185

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

  detect(entry) {
    const url = entry.api || entry.careers_url || '';
    if (typeof url !== 'string') return null;
    try {
      const host = new URL(url).host.toLowerCase();
      if (host === 'avature.net' || host.endsWith('.avature.net')) return { url };
    } catch {
      /* not absolute */
    }
    return null;
  },

  async fetch(entry, ctx) {
    const cfg = resolveConfig(entry);
    if (!cfg) throw new Error(`avature: cannot resolve origin for ${entry.name}`);
    const maxPages = Math.min(
      HARD_MAX_PAGES,
      Number.isFinite(entry.max_pages) && entry.max_pages > 0 ? Number(entry.max_pages) : DEFAULT_MAX_PAGES,
    );

    // Pagination key. An explicit `offset_param` pins it (and disables the
    // auto-switch below); otherwise start with `jobOffset` and self-heal. A
    // non-string/empty override falls back to the default so a malformed entry
    // can't produce `?=N`.
    const pinned = typeof entry.offset_param === 'string' && entry.offset_param.trim();
    let offsetParam = pinned ? entry.offset_param.trim() : PRIMARY_OFFSET_PARAM;
    let canHeal = !pinned; // once the key is pinned, never auto-switch

    const jobs = [];
    const seen = new Set();

    const getPage = async (param, page) => {
      const usp = new URLSearchParams(cfg.extraParams);

View on GitHub (pinned to e7abd431fc)