santifer/career-ops · error · Error

jobvite: cannot derive a company id for ${entry.name} — set

Error message

jobvite: cannot derive a company id for ${entry.name} — set company_eid: or an api: URL with ?c=

What it means

Thrown during fetch() when the provider cannot resolve a Jobvite companyEId by any of its three resolution paths: no company_eid: field, no api: URL with a c= query param, and no resolvable vanity slug from the careers_url. The XML feed requires the opaque companyEId (e.g. 'q6NaVfwI') which does not appear in the careers URL — so an entry lacking all three identifiers cannot build a feed URL and must fail loudly rather than silently return zero jobs.

Source

Thrown at providers/jobvite.mjs:294

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

  detect(entry) {
    const eid = resolveConfiguredEid(entry);
    if (eid) return { url: buildFeedUrl(eid) };
    // A vanity URL alone still identifies this provider; the eId is resolved
    // at fetch time via discovery.
    const slug = resolveSlug(entry);
    return slug ? { url: buildBoardUrl(slug) } : null;
  },

  async fetch(entry, ctx) {
    let eid = resolveConfiguredEid(entry);

    if (!eid) {
      const slug = resolveSlug(entry);
      if (!slug) throw new Error(`jobvite: cannot derive a company id for ${entry.name} — set company_eid: or an api: URL with ?c=`);
      const boardUrl = buildBoardFetchUrl(slug);
      assertJobviteHost(boardUrl);
      // redirect:'error' here, not 'manual'. A board that still redirects once
      // fr=true&nl=1 is present is a retired slug answering
      // search.jobvite.com?invalid=1, and that must fail loudly.
      const html = await fetchTextWithRetry(ctx, boardUrl, { redirect: 'error' }, RETRY_POLICY);
      eid = extractEidFromBoard(html);
      if (!eid) {
        throw new Error(
          `jobvite: could not find companyEId on ${boardUrl} for ${entry.name}. ` +
          `Set it explicitly with company_eid: (find it in the board page source as companyEId: '…').`,
        );
      }
    }

    const feedUrl = buildFeedUrl(eid);
    assertJobviteHost(feedUrl);
    try {

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Set company_eid: on the portal entry with the opaque ID (preferred — open the company's Jobvite board page, view source, find companyEId: '…').
  2. Alternatively, set an api: URL of the form https://app.jobvite.com/...?c=<eId>.
  3. Ensure careers_url is a valid Jobvite vanity URL (e.g. https://jobs.jobvite.com/<slug>) so the discovery path can resolve the eId at fetch time.

Example fix

# before (portals.yml) — no identifier
acme:
  provider: jobvite
  name: Acme

# after — explicit eId
acme:
  provider: jobvite
  name: Acme
  company_eid: q6NaVfwI
Defensive patterns

Strategy: validation

Validate before calling

function hasJobviteIdentifier(entry) {
  return Boolean(entry.company_eid)
    || (/\?c=/.test(entry.api || ''))
    || (/jobvite\.com/i.test(entry.careers_url || ''));
}
// before scan:
for (const e of jobviteEntries) {
  if (!hasJobviteIdentifier(e)) console.warn(`missing jobvite id: ${e.name}`);
}

Type guard

/** @param {any} entry @returns {boolean} */
function jobviteEntryIsComplete(entry) {
  return Boolean(entry && (
    entry.company_eid ||
    (typeof entry.api === 'string' && /[?&]c=/.test(entry.api)) ||
    (typeof entry.careers_url === 'string' && /jobvite\.com/i.test(entry.careers_url))
  ));
}

Prevention

When it happens

Trigger: A portals.yml job_boards entry marked provider: jobvite with a careers_url that is not a Jobvite vanity URL (extractSlug fails) and no company_eid or api field set; an entry where careers_url was deleted but company_eid was never added.

Common situations: Onboarding a new Jobvite tenant by copying an entry template and forgetting to fill in the identifier; an entry that relied on a careers_url which later changed shape so resolveSlug() no longer matches.

Related errors


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