santifer/career-ops · error · Error

wttj: unexpected Algolia response for query

Error message

wttj: unexpected Algolia response for query "${query}" — expected { hits: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}]

What it means

The wttj provider POSTs to Algolia and expects the JSON response to contain a hits array (Algolia's standard search result shape). If the parsed JSON is null, lacks hits, or hits is not an array, fetch throws this error listing the top-level keys actually received. This indicates the Algolia query failed at the API level (auth, invalid params, rate limit) or the response was intercepted by a proxy/challenge page.

Solutions

  1. Log or print the full response body/status for the failing query to see which keys were returned (the error lists them)
  2. Re-run the /api/env fetch and confirm the app id and api key are still valid for Algolia queries
  3. Check whether the response is an anti-bot challenge or proxy error and add appropriate headers/cookies or run from a different network
  4. If the keys look like an Algolia error object (message/status), read its message — usually invalid API key, invalid filters syntax, or quota exceeded

Example fix

// before: only checks shape, discards the error body
if (!json || !Array.isArray(json.hits)) { throw new Error(...); }
// after: surface the Algolia error message
if (!json || !Array.isArray(json.hits)) {
  if (json?.message && json?.status) {
    throw new Error(`wttj: Algolia error ${json.status}: ${json.message}`);
  }
  throw new Error(`wttj: unexpected Algolia response for query "${query}"`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify Algolia credentials still work before a batch run
const res = await fetch(algoliaUrl, { method: 'POST', headers, body: JSON.stringify({ params: 'query=test' }) });
if (!res.ok) throw new Error(`Algolia preflight failed: ${res.status} ${await res.text()}`);

Type guard

function isAlgoliaHitsResponse(json) {
  return !!json && typeof json === 'object' && Array.isArray(json.hits);
}

Try / catch

try {
  await scanWttj(entry);
} catch (e) {
  if (e.message.startsWith('wttj: unexpected Algolia response')) {
    console.warn('Algolia rejected the query — re-fetch /api/env creds, check for anti-bot pages or rate limits, then retry.');
  } else throw e;
}

Prevention

When it happens

Trigger: Algolia returns an error JSON body (e.g. {message, status} for 4xx), a Cloudflare/anti-bot HTML or JSON challenge replaces the response, the app id/api key from /api/env became invalid mid-run, or the request body/params are malformed so the response has no hits field.

Common situations: Rotated-out Algolia credentials producing 403 {"message":"..."} bodies; rate limiting (429) with a non-hits JSON; a corporate proxy returning an error page; WTTJ switching search backend so the endpoint no longer speaks Algolia.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/74df7ae66299f8e4. Report an issue: GitHub.

Appendix: source

Thrown at providers/wttj.mjs:238

      // faceted attributes; it never reaches a URL or host, so the assertHost
      // guard above still covers every request target.
      if (filters) params.set('filters', filters);
      const json = /** @type {any} */ (
        await ctx.fetchJson(url, {
          method: 'POST',
          redirect: 'error',
          headers: {
            'x-algolia-application-id': appId,
            'x-algolia-api-key': apiKey,
            // The client search key is referer-locked to the WTTJ site.
            referer: `${SITE_ORIGIN}/`,
            'content-type': 'application/json',
          },
          body: JSON.stringify({ params: params.toString() }),
        })
      );
      if (!json || !Array.isArray(json.hits)) {
        throw new Error(
          `wttj: unexpected Algolia response for query "${query}" — expected { hits: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}]`,
        );
      }
      for (const h of json.hits) {
        const job = normalizeWttjHit(h);
        if (job && !byUrl.has(job.url)) byUrl.set(job.url, job);
      }
    }
    return [...byUrl.values()];
  },
};

View on GitHub (pinned to aac998c7ed)