santifer/career-ops · error · Error
hecklerkoch: cannot resolve vacancy list for
Error message
hecklerkoch: cannot resolve vacancy list for ${entry.name} What it means
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.
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.
Example fix
// before (portals.yml) - name: Heckler & Koch provider: hecklerkoch // after - name: Heckler & Koch provider: hecklerkoch api: https://www.heckler-koch.com/careers/vacancies
Defensive patterns
Strategy: validation
Validate before calling
function hecklerkochEntryReady(entry) {
return typeof (entry?.api ?? entry?.careers_url) === 'string' && (entry.api ?? entry.careers_url).length > 0;
}
if (!hecklerkochEntryReady(entry)) console.warn(`entry ${entry.name} cannot resolve a hecklerkoch listing URL`); Type guard
const resolvableListEntry = (e) => typeof e?.api === 'string' && e.api.length > 0;
Try / catch
try {
await provider.fetch(entry, ctx);
} catch (err) {
if (err.message.startsWith('hecklerkoch: cannot resolve vacancy list')) {
console.error(`Set the listing/api URL for entry "${entry.name}" in portals.yml`);
return;
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- greenhouse: cannot derive API URL for
- arbeitnow: invalid URL
- ashby: invalid URL
- bamboohr: invalid URL
- breezy: cannot derive API URL for
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/64f136911629919c.
Report an issue: GitHub.
Appendix: source
Thrown at providers/hecklerkoch.mjs:86
seen.add(id);
out.push({ id, title, url });
}
return out;
}
/** @type {Provider} */
export default {
id: 'hecklerkoch',
detect(entry) {
const url = entry.api || entry.careers_url || '';
if (typeof url !== 'string') return null;
return resolveListUrl({ api: url }) ? { url } : null;
},
async fetch(entry, ctx) {
const listUrl = resolveListUrl(entry);
if (!listUrl) throw new Error(`hecklerkoch: cannot resolve vacancy list for ${entry.name}`);
const html = await ctx.fetchText(listUrl, { headers: { accept: 'text/html' } });
const rows = parseListing(html);
const jobs = [];
for (const row of rows) {
jobs.push({ title: row.title, url: row.url, company: entry.name, location: '' });
if (jobs.length >= MAX_JOBS) break;
}
return jobs;
},
};
View on GitHub (pinned to aac998c7ed)