santifer/career-ops · error · Error
arbeitnow: unexpected API response on page ${page} — expecte
Error message
arbeitnow: unexpected API response on page ${page} — expected { data: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}] What it means
arbeitnow's `fetch` expects each page JSON to be an object with a `data` array (the documented arbeitnow API shape). If the response is null or `data` is not an array, the provider throws rather than silently returning zero jobs — distinguishing an API contract break from a legitimately empty board.
Source
Thrown at providers/arbeitnow.mjs:115
/** @type {Provider} */
export default {
id: 'arbeitnow',
async fetch(entry, ctx) {
assertArbeitnowUrl(FEED_BASE);
const maxPages = resolveMaxPages(entry);
const fallbackCompany = entry?.name;
const out = [];
for (let page = 1; page <= maxPages; page++) {
// Build the page URL directly (do NOT follow links.next — it carries a
// featured `?search=` term that would narrow the board).
const url = `${FEED_BASE}?page=${page}`;
// redirect:'error' prevents SSRF via server-side redirects
const json = await ctx.fetchJson(url, { redirect: 'error' });
if (!json || !Array.isArray(json.data)) {
throw new Error(
`arbeitnow: unexpected API response on page ${page} — expected { data: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}]`,
);
}
for (const j of json.data) {
const normalized = normalizeArbeitnowJob(j, fallbackCompany);
if (normalized) out.push(normalized);
}
if (json.data.length < PER_PAGE) break; // short page → last page reached
}
return out;
},
};
View on GitHub (pinned to 9b17a8ac97)
Solutions
- Inspect the keys printed in the error to see what shape the API now returns.
- Reproduce the request (`https://www.arbeitnow.com/api/job-board-api?page=1`) in a browser/curl and compare to the expected `{ data: [...] }`.
- If the API renamed the array, update the `Array.isArray(json.data)` check and the `json.data.length < PER_PAGE` short-page logic.
- If the response is null, check for a non-JSON reply (HTML maintenance page) and verify the fetch headers.
Example fix
// before
if (!json || !Array.isArray(json.data)) {
throw new Error(`arbeitnow: unexpected API response on page ${page} ...`);
}
// after — tolerate a documented wrapper while still failing loudly on garbage
const rows = Array.isArray(json?.data) ? json.data : Array.isArray(json?.jobs) ? json.jobs : null;
if (!rows) {
throw new Error(`arbeitnow: unexpected API response on page ${page} — got keys: [${json ? Object.keys(json).join(', ') : 'null'}]`);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Probe one page at startup to confirm the API shape before the scan
const probe = await ctx.fetchJson(`${FEED_BASE}?page=1`, { redirect: 'error' });
if (!probe || !Array.isArray(probe.data)) {
throw new Error(`arbeitnow: API contract drift — top-level keys: [${probe ? Object.keys(probe).join(', ') : 'null'}]`);
} Type guard
/** @param {any} j */
function isArbeitnowFeed(j) {
return j !== null && typeof j === 'object' && Array.isArray(j.data);
} Try / catch
try {
const json = await ctx.fetchJson(url, { redirect: 'error' });
if (!isArbeitnowFeed(json)) throw new Error(`unexpected response — keys: [${json ? Object.keys(json).join(', ') : 'null'}]`);
// ...process json.data
} catch (err) {
// log the page + keys, continue to next page or surface a contract-drift alert
console.error(`arbeitnow page ${page}: ${err.message}`);
throw err;
} Prevention
- Add a startup contract probe so API drift fails fast with a clear message.
- Pin the response shape with a type guard and surface actual keys on mismatch.
- Watch for null responses (HTML maintenance pages) — they indicate a non-JSON reply, not contract drift.
When it happens
Trigger: `ctx.fetchJson(url, { redirect:'error' })` returns null (non-JSON / empty body) or an object whose `data` field is missing or not an array. The message lists the actual top-level keys (or 'null') for diagnosis.
Common situations: The arbeitnow API changed its payload shape (renamed `data`, wrapped it), returned an HTML error page parsed as null, hit a CDN error JSON (`{error: ...}`), or the endpoint moved.
Related errors
- payload must include at least one of: cv, articleDigest
- justjoin: unexpected API response — expected { data: [...] }
- workingnomads: unexpected API response — expected a JSON arr
- wttj: unexpected Algolia app id "${appId}"
- wttj: unexpected Algolia api key shape
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/28f2db7f7ffc90b9.
Report an issue: GitHub.