santifer/career-ops · error · Error
getonbrd: unexpected API response on page ${page} — expected
Error message
getonbrd: unexpected API response on page ${page} — expected { data: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}] What it means
getonbrd.mjs throws this in fetch() when the JSON body for a page is null/falsy or json.data is not an Array. The Get on Board JSON:API contract is { data: [...resources], meta: {...} }, so a missing or reshaped data array means the response is not a valid job feed page. The message includes the actual top-level keys (or 'null') to aid diagnosis.
Source
Thrown at providers/getonbrd.mjs:122
return job;
}
/** @type {Provider} */
export default {
id: 'getonbrd',
async fetch(entry, ctx) {
assertGetonbrdUrl(FEED_BASE);
const maxPages = resolveMaxPages(entry);
const fallbackCompany = entry?.name;
const out = [];
for (let page = 1; page <= maxPages; page++) {
const url = `${FEED_BASE}?per_page=${PER_PAGE}&expand[]=company&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(
`getonbrd: unexpected API response on page ${page} — expected { data: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}]`,
);
}
for (const j of json.data) {
const normalized = normalizeGetonbrdJob(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
- curl the failing page URL (https://www.getonbrd.com/api/v0/categories/programming/jobs?per_page=100&expand[]=company&page=N) and inspect the keys named in the message.
- If it is an error/maintenance envelope, retry shortly — usually transient.
- If the shape changed permanently, update the json.data extraction and the short-page break logic in getonbrd.mjs.
- Confirm expand[]=company and per_page=100 still match the documented API; an API tightening may reject the current query string.
Example fix
// before
if (!json || !Array.isArray(json.data)) { throw new Error(`getonbrd: unexpected API response ...`); }
// after (tolerate a renamed key, e.g. 'results')
const rows = Array.isArray(json?.data) ? json.data : Array.isArray(json?.results) ? json.results : null;
if (!rows) { throw new Error(`getonbrd: unexpected API response ...`); } Defensive patterns
Strategy: try-catch
Type guard
// Narrow a Get on Board response to the expected { data: [] } shape.
function isGetonbrdPage(json) {
return !!json && typeof json === 'object' && Array.isArray(json.data);
} Try / catch
// On non-first pages, treat a shape anomaly as end-of-feed instead of fatal.
try {
const json = await ctx.fetchJson(url, { redirect: 'error' });
if (!isGetonbrdPage(json)) {
if (page === 1) throw new Error('getonbrd: unexpected API response on page 1');
break;
}
} catch (err) {
if (page === 1) throw err;
console.error(`getonbrd: page ${page} failed — ${err.message}`);
break;
} Prevention
- Log the top-level keys on shape failures for fast diagnosis.
- Retry once on transient maintenance/error envelopes before surfacing.
- Track Get on Board API announcements for envelope changes.
When it happens
Trigger: The API returned an error envelope ({ message, errors }) with no data; a maintenance/HTML page was parsed into a non-standard object; the endpoint was versioned and moved jobs under a different key; a rate-limit response returned JSON without data; the body was empty (null json).
Common situations: Get on Board ships an API version bump that reshapes the envelope; the board is temporarily unavailable and returns an error object; a WAF/Cloudflare challenge returns interstitial JSON; invalid query params (e.g. an unknown expand) triggered an error response.
Related errors
- flowxtra: unexpected API response on page ${page} — expected
- glints: unexpected API response — ${JSON.stringify(json).sli
- gem: JobBoardList failed: ${listResult.errors[0]?.message ||
- glints: HTTP ${err.status} — ${detail}
- ${msg}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/695c7bfd620a9fc4.
Report an issue: GitHub.