santifer/career-ops · error · Error

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

Error message

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

What it means

Thrown by icims fetch() when resolveOrigin(entry) returns null. resolveOrigin walks [entry.api, entry.careers_url] and accepts only entries that are https URLs whose hostname ends in .icims.com, returning the origin. Anything else — wrong host, http scheme, non-URL, or both fields absent — returns null, and detect() returns null silently while fetch() throws.

Source

Thrown at providers/icims.mjs:114

      location: location ? decodeEntities(location[1].replace(/\s+/g, ' ').trim()) : '',
      // no postedAt — iCIMS list pages have no date; see enrichDate.
    });
  }
  return jobs;
}

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

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

  async fetch(entry, ctx) {
    const origin = resolveOrigin(entry);
    if (!origin) throw new Error(`icims: cannot derive portal origin for ${entry.name}`);
    const all = [];
    let prevFirstUrl = null;
    // Distinguishes "walked the whole board" from "stopped at the page cap".
    // Exhausting the cap silently would drop every later posting and look
    // identical to a complete board — the same failure mode the Workday
    // truncation tag exists to prevent.
    let reachedEnd = false;
    for (let pageNum = 0; pageNum < ICIMS_MAX_PAGES; pageNum++) {
      if (pageNum > 0) await sleep(INTER_PAGE_DELAY_MS, ctx);
      const html = await ctx.fetchText(searchUrl(origin, pageNum), { headers: HEADERS, redirect: 'error' });
      const pageJobs = parseIcimsSearchPage(html, origin, entry.name);
      if (pageJobs.length === 0) { reachedEnd = true; break; } // past the last page
      // Some tenants serve the last real page again for an out-of-range pr
      // instead of an empty one — a repeated first URL means we're looping.
      if (pageJobs[0].url === prevFirstUrl) { reachedEnd = true; break; }
      prevFirstUrl = pageJobs[0].url;
      all.push(...pageJobs);
    }

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Set careers_url to the canonical https://careers-{tenant}.icims.com/jobs/search?ss=1 form (or any https *.icims.com URL).
  2. If the tenant uses a branded domain that is genuinely iCIMS-hosted but not on icims.com, that host is intentionally unsupported by auto-detect — confirm the icims.com backend URL and set api/careers_url to it.
  3. Validate with detect(): provider.detect(entry) returning null means fetch() will throw this too.

Example fix

# before
- name: Acme
  provider: icims
  careers_url: https://careers.acme.com/jobs

# after
- name: Acme
  provider: icims
  careers_url: https://careers-acme.icims.com/jobs/search?ss=1
Defensive patterns

Strategy: validation

Validate before calling

const hit = icimsProvider.detect(entry);
if (!hit) {
  console.warn(`icims: ${entry.name} — api/careers_url must be an https *.icims.com URL`);
  continue;
}
const jobs = await icimsProvider.fetch(entry, ctx);

Type guard

/** True when the entry can resolve an iCIMS portal origin. */
function isIcimsDerivable(entry) {
  for (const raw of [entry?.api, entry?.careers_url]) {
    if (typeof raw !== 'string' || !raw) continue;
    try {
      const u = new URL(raw);
      if (u.protocol === 'https:' && u.hostname.endsWith('.icims.com')) return true;
    } catch { /* ignore */ }
  }
  return false;
}

Try / catch

try {
  const jobs = await icimsProvider.fetch(entry, ctx);
} catch (err) {
  if (/cannot derive portal origin/.test(err.message)) {
    console.error(`config: ${entry.name} — ${err.message}`);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: An entry tagged provider: icims whose careers_url/api is on a non-icims.com host (the company's branded domain that does not proxy iCIMS); an http:// URL (resolveOrigin requires https); a missing or non-string careers_url and no api; pasting a generic job-board URL against the icims provider.

Common situations: Some iCIMS tenants brand the portal onto their own domain (e.g. careers.acme.com) which still proxies icims.com on the backend but the hostname no longer ends in .icims.com; copy-pasting an http link; YAML misindentation leaving careers_url unset.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/6eb2798e1245084d. Report an issue: GitHub.