{"record":{"id":"30a0a8ef6ebe9508","repo":"santifer/career-ops","slug":"smartrecruiters-cannot-derive-api-url-for-entry","errorCode":null,"errorMessage":"smartrecruiters: cannot derive API URL for ${entry.name}","messagePattern":"smartrecruiters: cannot derive API URL for (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/smartrecruiters.mjs","lineNumber":70,"sourceCode":"}\n\nfunction resolveApiUrl(entry) {\n  const slug = resolveSlug(entry);\n  return slug ? buildPostingsUrl(slug, 0) : null;\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'smartrecruiters',\n\n  detect(entry) {\n    const apiUrl = resolveApiUrl(entry);\n    return apiUrl ? { url: apiUrl } : null;\n  },\n\n  async fetch(entry, ctx) {\n    const slug = resolveSlug(entry);\n    if (!slug) throw new Error(`smartrecruiters: cannot derive API URL for ${entry.name}`);\n\n    const all = [];\n    for (let page = 0; page < SR_MAX_PAGES; page++) {\n      const apiUrl = buildPostingsUrl(slug, page * SR_PAGE_SIZE);\n      assertSmartRecruitersUrl(apiUrl);\n      const json = await ctx.fetchJson(apiUrl, { redirect: 'error' });\n      const parsed = parseSmartRecruitersResponse(json, entry.name);\n      if (parsed.length === 0) break;\n      all.push(...parsed);\n      if (parsed.length < SR_PAGE_SIZE) break;  // last page (short)\n    }\n    return all;\n  },\n};\n\n/**\n * Parse a SmartRecruiters /postings response. Exported for unit tests.\n *","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/smartrecruiters.mjs#L52-L88","documentation":"resolveSlug walks entry.api then entry.careers_url and keeps the first value that is a valid HTTPS URL on careers.smartrecruiters.com or jobs.smartrecruiters.com whose first path segment is the company slug. If neither qualifies it returns null, and fetch throws because the postings API URL cannot be built. This is a configuration/detection mismatch: the entry does not expose a recognizable SmartRecruiters careers URL.","triggerScenarios":"entry.careers_url is a branded custom domain (e.g. https://jobs.continental.com) with no api: override; the URL uses http:// instead of https://; the host is not one of the two SR careers hosts; or the path has no slug segment (bare domain root). A manually-added provider: smartrecruiters entry with a non-SR URL also hits this.","commonSituations":"A company fronts SmartRecruiters behind a branded careers domain and the entry was auto-detected or hand-added with only the branded URL, so the slug cannot be recovered. The documented fix is to pin the slug via api: https://careers.smartrecruiters.com/<slug>.","solutions":["Pin the slug explicitly in portals.yml: api: https://careers.smartrecruiters.com/<slug> (keep the branded page as careers_url)","Alternatively set careers_url to the raw form https://careers.smartrecruiters.com/<slug> or https://jobs.smartrecruiters.com/<slug>","Verify the slug by opening the careers site and copying the first path segment of any posting URL","If the company is not on SmartRecruiters, remove provider: smartrecruiters and use the correct provider"],"exampleFix":"# before\n- name: Continental\n  provider: smartrecruiters\n  careers_url: https://jobs.continental.com\n# after\n- name: Continental\n  provider: smartrecruiters\n  careers_url: https://jobs.continental.com\n  api: https://careers.smartrecruiters.com/continental","handlingStrategy":"validation","validationCode":"// Validate a portal entry resolves a SmartRecruiters slug before handing it to fetch.\nimport sr from './providers/smartrecruiters.mjs';\nconst detected = sr.detect(entry);\nif (!detected) {\n  console.warn(`${entry.name}: smartrecruiters cannot derive slug — set api: https://careers.smartrecruiters.com/<slug>`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always run provider.detect(entry) before provider.fetch; null means the entry will throw.","For branded domains, always pin the slug with api: https://careers.smartrecruiters.com/<slug>.","Add a config lint pass that flags provider: smartrecruiters entries whose careers_url is not on a SR host and lacks an api: pin."],"tags":["config","smartrecruiters","slug","portals-yml","detection"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}