santifer/career-ops · error · Error

icims: cannot derive portal origin for

Error message

icims: cannot derive portal origin for ${entry.name}

What it means

The icims provider derives the portal origin (the tenant's *.icims.com base URL) from the portals.yml entry via resolveOrigin. If it cannot derive an origin, fetch() throws this error naming the entry, because without a base origin there is no search endpoint to page through.

Solutions

  1. Set the entry's careers_url (or the field resolveOrigin reads) to the company's iCIMS tenant URL, e.g. https://<tenant>.icims.com/jobs
  2. Find the iCIMS portal link from the company's careers page and update portals.yml
  3. Remove or disable the entry if the company no longer uses iCIMS
  4. Extend resolveOrigin only if you control the entry shape — prefer fixing the config

Example fix

// before (portals.yml)
careers_url: "https://acme.com/careers"
// after
careers_url: "https://acme.icims.com/jobs"
Defensive patterns

Strategy: validation

Validate before calling

function hasIcimsOrigin(entry) {
  if (!entry || typeof entry.name !== 'string') return false;
  const url = typeof entry.careers_url === 'string' ? entry.careers_url : '';
  try {
    const u = new URL(url);
    return /(^|\.)icims\.com$/.test(u.hostname) || typeof entry.portal === 'string';
  } catch { return false; }
}
// filter entries before fetch: entries.filter(hasIcimsOrigin)

Type guard

const isIcimsEntry = (e) => !!e && typeof e.careers_url === 'string'
  && (() => { try { return new URL(e.careers_url).hostname.endsWith('.icims.com'); } catch { return false; } })();

Try / catch

try {
  await icimsProvider.fetch(entry, ctx);
} catch (err) {
  if (/cannot derive portal origin/.test(err.message)) {
    console.warn(`fixing config for ${entry.name}: ${err.message}`);
    return [];
  }
  throw err;
}

Prevention

When it happens

Trigger: resolveOrigin(entry) returns falsy for an entry — the entry lacks the field icims derives the origin from (e.g. careers_url/portal host), or the URL does not match the expected iCIMS host pattern.

Common situations: A portals.yml entry was added with a plain careers page URL instead of the iCIMS tenant URL; the company migrated off iCIMS so the URL no longer matches the iCIMS pattern; a typo in the portal hostname.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at providers/icims.mjs:158

  id: 'icims',

  detect(entry) {
    const origin = resolveOrigin(entry);
    return origin ? { url: searchUrl(origin, 0) } : null;
  },

  /**
   * Walk a tenant's search pages. An entry may carry `fallback_urls`: other
   * hosts the same tenant could be served from (scan-ats-full.mjs builds them,
   * because the public dataset stores some tenants bare and some as a full
   * portal subdomain). A fallback is tried only when the previous host answers
   * 404 on its FIRST page, the one response that means "no board here". Any
   * other failure (throttle, timeout, DNS, a later-page 404) is rethrown as-is,
   * so dead-board tracking still reads it as "unknown", never "dead".
   */
  async fetch(entry, ctx) {
    const primary = resolveOrigin(entry);
    if (!primary) throw new Error(`icims: cannot derive portal origin for ${entry.name}`);
    const origins = [primary];
    for (const raw of Array.isArray(entry.fallback_urls) ? entry.fallback_urls : []) {
      // Same https + *.icims.com gate as the primary: a fallback can never
      // point the scanner at another host.
      const origin = resolveOrigin({ careers_url: raw });
      if (origin && !origins.includes(origin)) origins.push(origin);
    }
    let notFound;
    for (const origin of origins) {
      try {
        return await fetchPortal(origin, entry, ctx);
      } catch (err) {
        if (err?.status !== 404 || !err.firstPage) throw err;
        notFound = err;
      }
    }
    throw notFound;
  },

View on GitHub (pinned to e7abd431fc)