santifer/career-ops · error · Error
hackernews: unexpected item response for thread ${threadId}
Error message
hackernews: unexpected item response for thread ${threadId} What it means
Thrown by hackernews fetch() when the Algolia items API returns a response for the resolved thread id that is null or not a plain object. A valid thread item is an object with a children[] array; anything else means the item endpoint returned an unexpected payload for that threadId.
Source
Thrown at providers/hackernews.mjs:161
/** @type {Provider} */
export default {
id: 'hackernews',
async fetch(entry, ctx) {
// Step 1: Find the latest "Who is hiring?" story id.
const searchData = await ctx.fetchJson(SEARCH_URL, { redirect: 'error' });
const threadId = resolveLatestThreadId(searchData);
if (!threadId) {
throw new Error('hackernews: could not find "Ask HN: Who is hiring?" thread in search results');
}
const threadHnUrl = `https://news.ycombinator.com/item?id=${threadId}`;
// Step 2: Fetch the thread item (children = top-level job comments).
const item = await ctx.fetchJson(itemUrl(threadId), { redirect: 'error' });
if (!item || typeof item !== 'object') {
throw new Error(`hackernews: unexpected item response for thread ${threadId}`);
}
const children = /** @type {any} */ (item).children;
if (!Array.isArray(children)) return [];
// Step 3: Parse each comment.
const jobs = [];
for (const child of children) {
// Skip deleted / dead / empty comments.
if (!child || child.deleted || child.dead) continue;
const text = typeof child.text === 'string' ? child.text : '';
if (!text.trim()) continue;
const parsed = parseHnComment(text, threadHnUrl);
if (!parsed) continue;
jobs.push({
title: parsed.title,View on GitHub (pinned to 9b17a8ac97)
Solutions
- Retry the scan — if the threadId was transiently bad, the next run resolves a fresh one.
- Confirm the item endpoint manually: open https://hn.algolia.com/api/v1/items/{threadId} and check it returns an object with children[].
- If the thread is genuinely dead/deleted, wait for the next monthly thread (this is a data condition, not a code bug).
- Ensure ctx.fetchJson surfaces non-2xx as errors rather than returning parsed error bodies.
Defensive patterns
Strategy: retry
Validate before calling
// After resolving threadId, sanity-check the item before relying on it.
const item = await ctx.fetchJson(itemUrl(threadId), { redirect: 'error' });
if (!item || typeof item !== 'object') {
throw new Error(`hackernews: thread ${threadId} returned a non-object item — likely dead/deleted`);
} Type guard
/** A valid Algolia item response: an object (children[] checked separately). */
function isHnItem(value) {
return !!value && typeof value === 'object' && !Array.isArray(value);
} Try / catch
try {
return await hackernewsProvider.fetch(entry, ctx);
} catch (err) {
if (/unexpected item response for thread/.test(err.message)) {
// The threadId may point at a now-deleted story; a fresh run resolves a new id.
console.warn(`hackernews: transient item response — will retry next scan`);
return [];
}
throw err;
} Prevention
- Treat a non-object item as transient (deleted/stale id) and let the next scan resolve a fresh thread.
- Confirm the Algolia items endpoint directly when the error persists to rule out a rate limit returning a non-object body.
- Keep ctx.fetchJson strict: surface non-2xx as rejections so error pages do not reach the shape check.
When it happens
Trigger: The threadId resolved from step 1 points at a story that has since been deleted/dead on HN (Algolia returns null for dead items); a transient Algolia 200-with-null; the items endpoint rate-limited and returned a non-object error body; the id is valid as a search hit but stale by the time the item fetch runs.
Common situations: A thread flagged/deleted shortly after posting; Algolia eventual-consistency lag between the search index and the items index; rate limiting after many sequential scans; an intermediary returning an HTML error page that parsed to a non-object.
Related errors
- hackernews: could not find "Ask HN: Who is hiring?" thread i
- himalayas: unexpected API response - expected { jobs: [...]
- ibm: unexpected API response — expected hits.hits[], got key
- jobicy: unexpected API response — expected { jobs: [...] },
- DNS resolution returned no addresses for ${hostname}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/6210d5140243ca7a.
Report an issue: GitHub.