{"record":{"id":"8f0c7e4b4ca6fb68","repo":"santifer/career-ops","slug":"radancy-cannot-resolve-search-jobs-url-for-entr","errorCode":null,"errorMessage":"radancy: cannot resolve search-jobs URL for ${entry.name}","messagePattern":"radancy: cannot resolve search-jobs URL for (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/radancy.mjs","lineNumber":273,"sourceCode":"function resolveMaxJobs(entry) {\n  const v = entry?.max_jobs;\n  if (Number.isInteger(v) && v > 0) return v;\n  return DEFAULT_MAX_JOBS;\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'radancy',\n\n  detect() {\n    // Branded hosts carry no stable Radancy token in the URL — wire explicitly\n    // with `provider: radancy`. No auto-detection.\n    return null;\n  },\n\n  async fetch(entry, ctx) {\n    const listUrl = resolveListUrl(entry);\n    if (!listUrl) throw new Error(`radancy: cannot resolve search-jobs URL for ${entry.name}`);\n    const origin = new URL(listUrl).origin;\n\n    const wait = (ms) => (ctx.sleep ? ctx.sleep(ms) : new Promise((r) => setTimeout(r, ms)));\n    const maxPages = resolveMaxPages(entry);\n    const maxJobs = resolveMaxJobs(entry);\n    const jobs = [];\n    const seen = new Set();\n    // Proof of life across BOTH transports: any resolved request — including a\n    // fragment 200 that parses to zero rows — proves the tenant is reachable,\n    // so a later HTML page-1 failure must not read as \"unreachable\".\n    let succeededOnce = false;\n\n    // ── Preferred transport: the JSON results fragment ───────────────────────\n    // Tried first because on legacy-markup tenants the ?p=N HTML page carries a\n    // multi-megabyte facet blob per page (see the transport note up top). Any\n    // failure here — non-JSON, no results, endpoint absent — falls through to\n    // the HTML walk below, so tenants without this endpoint are unaffected.\n    if (typeof ctx.fetchJson === 'function') {","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/radancy.mjs#L255-L291","documentation":"The radancy provider's fetch() throws when resolveListUrl(entry) returns null. resolveListUrl reads entry.api || entry.careers_url, parses it, requires an http: or https: protocol, and normalizes the path to a /<lang>/search-jobs endpoint. Because Radancy hosts branded career sites on arbitrary domains, detect() always returns null — the provider must be wired explicitly with provider: radancy plus a search-jobs api/careers_url.","triggerScenarios":"fetch() is called on an entry missing both api and careers_url; the URL is unparseable by new URL(); the protocol is neither http: nor https: (e.g. a mailto: or relative path); detect() was bypassed and fetch invoked directly on a non-Radancy entry.","commonSituations":"A portals.yml row sets provider: radancy but forgets the api: or careers_url: line; the entry was built from an API response that did not include a careers_url; the URL has a leading space or smart-quote characters from copy-paste.","solutions":["Add an api: or careers_url: to the entry pointing at the tenant's search-jobs page (e.g. https://careers.munichre.com/search-jobs or https://careers.acme.com/en/search-jobs).","Confirm the entry is tagged provider: radancy — auto-detection is intentionally disabled for branded hosts.","Verify the URL string is a well-formed absolute http(s) URL with no leading/trailing whitespace.","Run detect(entry) before fetch; since detect always returns null for radancy, ensure you are dispatching by the explicit provider field instead."],"exampleFix":"# before — portals.yml entry with provider but no URL\n- name: Munich Re\n  provider: radancy\n# after\n- name: Munich Re\n  provider: radancy\n  api: https://careers.munichre.com/search-jobs","handlingStrategy":"validation","validationCode":"// radancy detect() always returns null — must dispatch by explicit provider field\nfunction shouldRunRadancy(entry) {\n  if (entry.provider !== 'radancy') return false;\n  const raw = entry.api || entry.careers_url || '';\n  try {\n    const u = new URL(raw);\n    return u.protocol === 'http:' || u.protocol === 'https:';\n  } catch { return false; }\n}\nif (!shouldRunRadancy(entry)) {\n  console.warn(`skip ${entry.name}: radancy needs provider:radancy + http(s) api/careers_url`);\n}","typeGuard":"null","tryCatchPattern":"try {\n  await provider.fetch(entry, ctx);\n} catch (e) {\n  if (/cannot resolve search-jobs URL/.test(e.message)) {\n    console.warn(`[skip] ${entry.name}: add api/careers_url for radancy`);\n  } else throw e;\n}","preventionTips":["Always set provider: radancy explicitly — auto-detection is intentionally disabled.","Include an api: or careers_url: pointing at the tenant's search-jobs page in every radancy entry.","Validate the entry has an http(s) URL before invoking fetch."],"tags":["config","provider","radancy","missing-url","resolution","branded-domain"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}