santifer/career-ops · error · Error
successfactors: cannot resolve origin for
Error message
successfactors: cannot resolve origin for ${entry.name} What it means
The successfactors provider must resolve each entry to a concrete tenant origin/config via resolveConfig(entry). When the entry's URL matches no known SuccessFactors pattern and no explicit origin is configured, it throws with the entry's name. This is a fail-fast for entries the provider genuinely cannot talk to.
Solutions
- Set an explicit origin/sfVariant (e.g. sfVariant: csb) in the entry so resolveConfig succeeds
- Point careers_url at the actual SuccessFactors tenant URL (careers.xx.successfactors.eu or *.jobs2web.com)
- Confirm the company still uses SuccessFactors; if it moved to another ATS, switch the entry's provider
- Check resolveConfig's accepted patterns in providers/successfactors.mjs and align the URL
Example fix
// before - name: Acme provider: successfactors careers_url: 'https://acme.com/careers' // after - name: Acme provider: successfactors careers_url: 'https://acme.successfactors.eu/careers' # or: sfVariant: csb
Defensive patterns
Strategy: validation
Validate before calling
const SF_RE = /(successfactors\.(eu|com)|jobs2web\.com)/i;
if (String(entry.provider) === 'successfactors' && !(entry.careers_url && SF_RE.test(entry.careers_url))) {
throw new Error(`${entry.name}: successfactors needs a careers_url on a successfactors.eu/com or jobs2web.com host (or explicit sfVariant/origin)`);
} Type guard
null
Try / catch
try {
offers = await provider.fetch(entry, ctx);
} catch (e) {
if (e.message.startsWith('successfactors: cannot resolve origin')) {
console.warn(`${entry.name}: provider cannot map URL to an SF tenant — fix entry config`);
return [];
}
throw e;
} Prevention
- Point entries at the real SF tenant URL (careers.*.successfactors.eu or *.jobs2web.com)
- Set sfVariant: csb explicitly for CSB tenants
- Re-verify entries when a company announces an ATS migration
- Run audit-portals.mjs after adding companies
When it happens
Trigger: A portals.yml entry has provider: successfactors but its careers_url matches neither successfactors.eu/com nor jobs2web.com patterns, or lacks the URL fields resolveConfig expects; entry.sfVariant/origin hints are missing for a tenant needing them.
Common situations: A company migrated off SuccessFactors so the URL no longer matches; someone pointed the successfactors provider at a generic careers page; a custom vanity domain not covered by the regexes was configured without explicit config.
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
- radancy: cannot resolve search-jobs URL for
- comeet: URL path must be the careers-api endpoint
- consider: needs an https careers_url on a public host
- csod: cannot resolve careersite URL for
- flowxtra: untrusted hostname
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/56f40d550a5a8a04.
Report an issue: GitHub.
Appendix: source
Thrown at providers/successfactors.mjs:417
startrow += tiles.length;
}
// The cap is checked between pages, so the last page can overshoot it.
return jobs.slice(0, MAX_JOBS);
}
/** @type {Provider} */
export default {
id: 'successfactors',
detect(entry) {
const url = entry.api || entry.careers_url || '';
if (/successfactors\.(eu|com)|jobs2web\.com/i.test(url)) return { url };
return null;
},
async fetch(entry, ctx) {
const cfg = resolveConfig(entry);
if (!cfg) throw new Error(`successfactors: cannot resolve origin for ${entry.name}`);
// Explicit opt-in goes straight to CSB. RMK tenants (the majority) run the
// tile scraper; only when it comes back empty — the CSB empty-shell
// signature — do we auto-fall back to the JSON API, so an unflagged CSB
// tenant still works and a genuinely-empty RMK board costs one extra probe.
if (String(entry.sfVariant || '').toLowerCase() === 'csb') {
return fetchCsb(entry, cfg, ctx);
}
const rmkJobs = await fetchRmk(entry, cfg, ctx);
if (rmkJobs.length > 0) return rmkJobs;
// RMK answered (healthy, possibly legitimately empty) — the CSB call here
// is only a probe for the empty-shell signature, so it must not turn a
// failing/absent CSB endpoint into a dead-board throw.
return fetchCsb(entry, cfg, ctx, { probe: true });
},
};
View on GitHub (pinned to aac998c7ed)