{"record":{"id":"56f40d550a5a8a04","repo":"santifer/career-ops","slug":"successfactors-cannot-resolve-origin-for-entry","errorCode":null,"errorMessage":"successfactors: cannot resolve origin for ${entry.name}","messagePattern":"successfactors: cannot resolve origin for (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/successfactors.mjs","lineNumber":417,"sourceCode":"    startrow += tiles.length;\n  }\n  // The cap is checked between pages, so the last page can overshoot it.\n  return jobs.slice(0, MAX_JOBS);\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'successfactors',\n\n  detect(entry) {\n    const url = entry.api || entry.careers_url || '';\n    if (/successfactors\\.(eu|com)|jobs2web\\.com/i.test(url)) return { url };\n    return null;\n  },\n\n  async fetch(entry, ctx) {\n    const cfg = resolveConfig(entry);\n    if (!cfg) throw new Error(`successfactors: cannot resolve origin for ${entry.name}`);\n\n    // Explicit opt-in goes straight to CSB. RMK tenants (the majority) run the\n    // tile scraper; only when it comes back empty — the CSB empty-shell\n    // signature — do we auto-fall back to the JSON API, so an unflagged CSB\n    // tenant still works and a genuinely-empty RMK board costs one extra probe.\n    if (String(entry.sfVariant || '').toLowerCase() === 'csb') {\n      return fetchCsb(entry, cfg, ctx);\n    }\n    const rmkJobs = await fetchRmk(entry, cfg, ctx);\n    if (rmkJobs.length > 0) return rmkJobs;\n    // RMK answered (healthy, possibly legitimately empty) — the CSB call here\n    // is only a probe for the empty-shell signature, so it must not turn a\n    // failing/absent CSB endpoint into a dead-board throw.\n    return fetchCsb(entry, cfg, ctx, { probe: true });\n  },\n};\n","sourceCodeStart":399,"sourceCodeEnd":434,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/successfactors.mjs#L399-L434","documentation":"resolveConfig parses entry.api or entry.careers_url and derives the RMK/CSB endpoint origins; it returns null only if new URL throws or the protocol is not http/https. fetch throws when that happens. Note detect() matches on a loose regex (successfactors.(eu|com)|jobs2web.com) against the raw string, so a string can pass detection yet fail URL parsing — and a provider: successfactors override skips detection entirely.","triggerScenarios":"The entry string contains 'successfactors.com' (so detect's regex matches) but is not a valid absolute URL, e.g. 'successfactors.com/careers' with no scheme. Or provider: successfactors is set but api/careers_url is missing or malformed. A protocol like ftp:// would also fail the http/https gate.","commonSituations":"A manually-added entry omits the https:// scheme; YAML mis-parsing produced a non-string; or provider: successfactors was force-set on an entry that has no usable URL.","solutions":["Provide a full absolute URL with scheme: https://careers.example.com or https://<tenant>.successfactors.com","Ensure the protocol is http or https (https strongly preferred)","If using provider: successfactors as an override, also set careers_url or api to the valid tenant URL","Verify the URL still resolves in a browser — a decommissioned tenant origin can also yield odd responses upstream"],"exampleFix":"# before\n- name: Acme\n  provider: successfactors\n  careers_url: successfactors.com/acme/careers\n# after\n- name: Acme\n  provider: successfactors\n  careers_url: https://acme.successfactors.com/careers","handlingStrategy":"validation","validationCode":"// Validate the entry URL is parseable http(s) before successfactors.fetch.\nfunction resolvableOrigin(v) {\n  try {\n    const u = new URL(v);\n    return u.protocol === 'http:' || u.protocol === 'https:';\n  } catch { return false; }\n}\nif (!resolvableOrigin(entry.api || entry.careers_url)) {\n  console.warn(`${entry.name}: successfactors needs a valid http(s) URL`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include the https:// scheme; detect's regex can match a scheme-less string that URL() then rejects.","When setting provider: successfactors as an override, also set a valid api/careers_url.","Lint entries whose URL string matches the detect regex but fails new URL()."],"tags":["config","successfactors","url-validation","portals-yml","detection"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}