santifer/career-ops · error · Error

workday: cannot derive CXS endpoint for

Error message

workday: cannot derive CXS endpoint for ${entry.name}

What it means

The Workday provider posts to a CXS (Candidate Experience Service) endpoint derived from the entry via resolveEndpoint. When the entry's api/careers_url cannot be resolved to a CXS endpoint, fetch throws before making any request.

Solutions

  1. Provide the entry's api field with the full Workday CXS endpoint URL
  2. Check the careers_url matches the Workday CXS pattern (…/wday/cxs/<tenant>/<site>/jobs) and fix it
  3. Confirm the tenant/site names by loading the company's careers page; correct the entry config

Example fix

// before
{ name: 'Acme', careers_url: 'https://acme.wd3.myworkdayjobs.com/careers' }
// after
{ name: 'Acme', api: 'https://acme.wd3.myworkdayjobs.com/wday/cxs/acme/careers/jobs' }
Defensive patterns

Strategy: validation

Validate before calling

function hasWorkdayCxs(entry) {
  const src = entry.api || entry.careers_url || '';
  return /myworkdayjobs\.com\/wday\/cxs\/[\w-]+\/[\w-]+/i.test(src) || /wday\/cxs/.test(src);
}

Type guard

const hasWorkdayCxs = (e) => /\/wday\/cxs\/[\w-]+\/[\w-]+/i.test(e.api || e.careers_url || '');

Try / catch

try { jobs = await workday.fetch(entry, ctx); } catch (e) { if (e.message.startsWith('workday: cannot derive CXS endpoint')) { console.warn(`${entry.name}: set entry.api to the full CXS /wday/cxs/<tenant>/<site>/jobs URL`); jobs = []; } else throw e; }

Prevention

When it happens

Trigger: fetch(entry, ctx) with an entry lacking a resolvable Workday endpoint — no api field, a non-Workday careers_url, or a careers_url that does not match Workday CXS URL patterns.

Common situations: A portals.yml company entry where the careers page is Workday Classic (not CXS), a wrong tenant hostname, or a company that migrated off Workday.

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-16). Data as JSON: /api/errors/25f313deadfad365. Report an issue: GitHub.

Appendix: source

Thrown at providers/workday.mjs:565

  /**
   * Fetch all job postings for a Workday-backed entry, paginating through
   * the tenant's CXS API.
   *
   * Some tenants front their CXS API with Cloudflare bot management (seen
   * live: geico) that 500s requests missing ordinary browser headers — the
   * default UA/accept-language-less request trips it even over plain HTTPS
   * with no other red flags. A real Chrome UA + accept-language + matching
   * origin/referer clears it without needing per-tenant config (same fix
   * as providers/glints.mjs's firewall).
   *
   * @param {{ name?: string, api?: string, careers_url?: string, max_pages?: number }} entry
   * @param {{ fetchJson: (url: string, opts?: object) => Promise<any>, sinceMs?: number, maxPages?: number, syntheticEntries?: boolean }} ctx
   * @returns {Promise<Array<{title: string, url: string, company: string, location: string, postedAt?: number}>>}
   */
  async fetch(entry, ctx) {
    const ep = resolveEndpoint(entry);
    if (!ep) throw new Error(`workday: cannot derive CXS endpoint for ${entry.name}`);

    const postOpts = {
      method: 'POST',
      redirect: 'error',
      headers: {
        'content-type': 'application/json',
        accept: 'application/json',
        'user-agent': BROWSER_LIKE_USER_AGENT,
        'accept-language': 'en-US,en;q=0.9',
        origin: ep.origin,
        referer: `${ep.jobBase}/`,
      },
    };
    const makeBody = (offset, appliedFacets) => JSON.stringify({ limit: PAGE_SIZE, offset, searchText: '', appliedFacets });
    const sinceMs = typeof ctx?.sinceMs === 'number' ? ctx.sinceMs : null;
    const maxPages = resolveMaxPages(entry);

    // Honor a context page cap — verify-portals' liveness probe sets

View on GitHub (pinned to e7abd431fc)