santifer/career-ops · error · Error

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

Error message

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

What it means

Workday auto-detects a tenant by matching entry.api then entry.careers_url against ^https://([\w-]+)\.(wd[\w-]*)\.myworkdayjobs\.com/(?:[a-z]{2}-[A-Z]{2}/)?([^/?#]+). resolveEndpoint returns null when neither matches, and fetch() throws because it cannot build the CXS POST URL (/wday/cxs/<tenant>/<site>/jobs).

Source

Thrown at providers/workday.mjs:176

  /**
   * 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) => JSON.stringify({ limit: PAGE_SIZE, offset, searchText: '', appliedFacets: {} });
    const sinceMs = typeof ctx?.sinceMs === 'number' ? ctx.sinceMs : null;

    const first = await fetchJsonWithRetry(ctx, ep.api, { ...postOpts, body: makeBody(0) }, RETRY_POLICY);
    const jobs = parseWorkdayResponse(first, entry);

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Set api: https://<tenant>.<instance>.myworkdayjobs.com/<site> on the entry (e.g. https://23andme.wd5.myworkdayjobs.com/23).
  2. Or set careers_url to that same tenant URL.
  3. Verify the instance segment matches the wd… pattern (wd1, wd5, …) and the site segment is present.
  4. For branded pages, keep careers_url as the branded page AND add api: with the raw tenant URL — the resolver tries api: first.

Example fix

# before
- name: PTC
  provider: workday
  careers_url: https://www.ptc.com/en/careers
# after
- name: PTC
  provider: workday
  careers_url: https://www.ptc.com/en/careers
  api: https://ptc.wd1.myworkdayjobs.com/PTC
Defensive patterns

Strategy: validation

Validate before calling

const WD_RE = /^https:\/\/([\w-]+)\.(wd[\w-]*)\.myworkdayjobs\.com\/(?:[a-z]{2}-[A-Z]{2}\/)?([^\/?#]+)/;
function workdayEndpointResolvable(entry) {
  for (const u of [entry.api, entry.careers_url]) {
    if (typeof u === "string" && WD_RE.test(u)) return true;
  }
  return false;
}
// before scan
if (entry.provider === "workday" && !workdayEndpointResolvable(entry)) {
  console.warn(`skip ${entry.name}: set api: to the myworkdayjobs.com tenant URL`);
  continue;
}

Type guard

const isWorkdayTenantUrl = (u) => typeof u === "string" &&
  /^https:\/\/([\w-]+)\.(wd[\w-]*)\.myworkdayjobs\.com\/(?:[a-z]{2}-[A-Z]{2}\/)?([^\/?#]+)/.test(u);

Prevention

When it happens

Trigger: An entry marked provider: workday whose api and careers_url are both missing, both branded domains (e.g. https://www.ptc.com/en/careers), or whose tenant URL has an unusual locale/path segment the regex rejects (e.g. lowercase-only locale, missing site segment, non-wd instance subdomain).

Common situations: Company has a branded careers page backed by Workday but the entry does not also set api: to the raw myworkdayjobs.com tenant URL; the instance segment is not a wd… subdomain; the locale path is malformed.

Related errors


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