santifer/career-ops · error
csod: cannot resolve careersite URL for
Error message
csod: cannot resolve careersite URL for ${entry.name} What it means
The CSOD (Cornerstone OnDemand) provider's fetch calls resolveConfig(entry) to obtain a careersite URL configuration it knows how to drive; when the entry yields no such config it throws this error. The provider needs the careersite path shape to bootstrap the anonymous bearer token and session cookies, so an unresolvable URL is a hard stop before any network call. It indicates the entry's csod configuration is absent or malformed.
Solutions
- Set the entry's careersite URL to the full CSOD careersite URL with the expected path shape (compare with a working csod entry in portals.yml).
- Verify the URL matches the careersite path shape resolveConfig expects — inspect resolveConfig in providers/csod.mjs for the exact shape test.
- If the tenant's URL structure changed, rediscover the new careersite URL from the live site and update the entry.
- Confirm the config key name (url/api) matches what resolveConfig reads — a misnamed key yields null and this error.
Example fix
// before - name: mycompany provider: csod // after - name: mycompany provider: csod url: https://mycompany.csod.com/uxp/career-site/...
Defensive patterns
Strategy: validation
Validate before calling
if (entry.provider === 'csod' && !entry.url) { throw new Error(`csod entry '${entry.name}' is missing the careersite url`); } Type guard
const hasCsodUrl = (entry) => typeof entry.url === 'string' && entry.url.startsWith('https://') && entry.url.includes('.csod.com/'); Try / catch
try {
const jobs = await provider.fetch(entry, ctx);
} catch (err) {
if (err.message.startsWith('csod: cannot resolve careersite URL')) {
console.warn(`Skipping ${entry.name}: careersite URL missing or wrong path shape`);
return null;
}
throw err;
} Prevention
- Copy the exact careersite URL (with the expected path shape) from a working csod entry
- Check resolveConfig's shape test in providers/csod.mjs before adding a new csod tenant
- Re-verify csod URLs if a tenant migrates their careersite structure
- Validate config keys (url/api) against what resolveConfig reads when onboarding a new entry
When it happens
Trigger: Scanning an entry routed to the csod provider whose careersite/api URL is missing or does not match the expected careersite path shape, so resolveConfig returns null.
Common situations: Configuring a Cornerstone-hosted company with a generic careers-page URL that lacks the csod careersite path shape; omitting the url/api key on the entry; a tenant changing their careersite URL structure so the previously working entry no longer resolves; typo-ing the config key.
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
- comeet: cannot derive API URL for
- comeet: URL path must be the careers-api endpoint
- consider: needs a 'consider_board' id in portals.yml
- consider: needs an https careers_url on a public host
- flowxtra: untrusted hostname
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/e40decd48c929e79.
Report an issue: GitHub.
Appendix: source
Thrown at providers/csod.mjs:181
if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES);
return MAX_PAGES;
}
/** @type {Provider} */
export default {
id: 'csod',
detect(entry) {
const url = entry.api || entry.careers_url || '';
if (typeof url !== 'string') return null;
// Host check (not a path substring) so evil.com/x.csod.com can't spoof it,
// and the URL must carry the careersite path shape we know how to drive.
return resolveConfig({ api: url }) ? { url } : null;
},
async fetch(entry, ctx) {
const cfg = resolveConfig(entry);
if (!cfg) throw new Error(`csod: cannot resolve careersite URL for ${entry.name}`);
// The bootstrap page yields two things, not one: the anonymous bearer
// token, and — on some tenants — the session cookies the search API
// insists on. careers-kln rejects an otherwise valid token+body with
// "HTTP 401 CSOD Unauthorized" until those cookies come back with it, so
// the token alone is not a sufficient credential. Prefer ctx.fetchResponse
// to see Set-Cookie; fall back to fetchText when the caller's ctx predates
// it (older embedders and test mocks), which keeps the pre-cookie
// behaviour intact for tenants that never needed it.
//
// cfg.homeUrl and cfg.searchApi are both built from the same parsed
// origin, so replaying these cookies cannot reach a third-party host.
// redirect:'error' on the bootstrap keeps that true: origin validation
// covers the URL we ask for, not wherever a 3xx would send us.
let html;
let cookie = '';
if (typeof ctx.fetchResponse === 'function') {
const res = await ctx.fetchResponse(cfg.homeUrl, { redirect: 'error', headers: { accept: 'text/html' } });View on GitHub (pinned to aac998c7ed)