{"record":{"id":"64f136911629919c","repo":"santifer/career-ops","slug":"hecklerkoch-cannot-resolve-vacancy-list-for-ent","errorCode":null,"errorMessage":"hecklerkoch: cannot resolve vacancy list for ${entry.name}","messagePattern":"hecklerkoch: cannot resolve vacancy list for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/hecklerkoch.mjs","lineNumber":86,"sourceCode":"    seen.add(id);\n    out.push({ id, title, url });\n  }\n  return out;\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'hecklerkoch',\n\n  detect(entry) {\n    const url = entry.api || entry.careers_url || '';\n    if (typeof url !== 'string') return null;\n    return resolveListUrl({ api: url }) ? { url } : null;\n  },\n\n  async fetch(entry, ctx) {\n    const listUrl = resolveListUrl(entry);\n    if (!listUrl) throw new Error(`hecklerkoch: cannot resolve vacancy list for ${entry.name}`);\n    const html = await ctx.fetchText(listUrl, { headers: { accept: 'text/html' } });\n    const rows = parseListing(html);\n    const jobs = [];\n    for (const row of rows) {\n      jobs.push({ title: row.title, url: row.url, company: entry.name, location: '' });\n      if (jobs.length >= MAX_JOBS) break;\n    }\n    return jobs;\n  },\n};\n","sourceCodeStart":68,"sourceCodeEnd":97,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/hecklerkoch.mjs#L68-L97","documentation":"The Heckler & Koch provider builds a vacancy-list URL from the portal entry via resolveListUrl and throws this error when that returns null, i.e. when neither an api URL nor a derivable listing URL can be produced from the entry. Without a list URL the provider cannot fetch the HTML listing to parse.","triggerScenarios":"A job_boards entry with provider: hecklerkoch missing both the expected api/list URL field and any careers_url shape that resolveListUrl can convert; or entry.api resolving to a non-string.","commonSituations":"Config entry added without the listing URL, key renamed or misspelled in portals.yml, or the careers site structure changed so the previously derivable URL no longer resolves.","solutions":["Set the explicit listing/API URL on the entry in portals.yml so resolveListUrl succeeds.","Compare the entry against other working hecklerkoch-style entries to find the expected field name.","Re-check the Heckler & Koch careers page — if the listing moved, update resolveListUrl in providers/hecklerkoch.mjs.","Inspect resolveListUrl in providers/hecklerkoch.mjs for the exact accepted shapes."],"exampleFix":"// before (portals.yml)\n- name: Heckler & Koch\n  provider: hecklerkoch\n// after\n- name: Heckler & Koch\n  provider: hecklerkoch\n  api: https://www.heckler-koch.com/careers/vacancies","handlingStrategy":"validation","validationCode":"function hecklerkochEntryReady(entry) {\n  return typeof (entry?.api ?? entry?.careers_url) === 'string' && (entry.api ?? entry.careers_url).length > 0;\n}\nif (!hecklerkochEntryReady(entry)) console.warn(`entry ${entry.name} cannot resolve a hecklerkoch listing URL`);","typeGuard":"const resolvableListEntry = (e) => typeof e?.api === 'string' && e.api.length > 0;","tryCatchPattern":"try {\n  await provider.fetch(entry, ctx);\n} catch (err) {\n  if (err.message.startsWith('hecklerkoch: cannot resolve vacancy list')) {\n    console.error(`Set the listing/api URL for entry \"${entry.name}\" in portals.yml`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Set the explicit api/listing URL on the entry rather than relying on derivation.","Validate per-provider required fields when loading portals.yml.","Re-verify the careers page structure after site redesigns and update resolveListUrl.","Copy a known-good entry of the same provider as a template."],"tags":["config","url","scraper","hecklerkoch"],"backgroundTag":"invalid-config-value","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}