santifer/career-ops · error · Error

torre: unexpected API response — expected { results: [...] }

Error message

torre: unexpected API response — expected { results: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}]

What it means

After posting the search body to the Torre API, fetch() validates the JSON response has a 'results' array. Anything else — null body, an error object, a wrapped envelope — throws this error listing the keys actually received. This check fails the whole fetch (Torre does a single search request, unlike Muse's tolerant pagination).

Source

Thrown at providers/torre.mjs:218

    assertTorreUrl(SEARCH_ENDPOINT);
    const body = JSON.stringify(buildTorreQuery(entry));
    const fallbackCompany = entry?.name;

    // Exactly one request: the endpoint caps at 20 rows and ignores every
    // pagination form, so a loop could only refetch the same page (quirk 2).
    // ctx.maxPages needs no handling for the same reason — one page is all
    // there is, which is already what the health probe wants.
    const url = `${SEARCH_ENDPOINT}?offset=0&size=${PAGE_SIZE}`;
    // redirect:'error' prevents SSRF via server-side redirects
    const json = await ctx.fetchJson(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body,
      redirect: 'error',
    });

    if (!json || !Array.isArray(json.results)) {
      throw new Error(
        `torre: unexpected API response — expected { results: [...] }, got keys: [${json ? Object.keys(json).join(', ') : 'null'}]`,
      );
    }

    const out = [];
    const seen = new Set();
    for (const o of json.results) {
      const normalized = normalizeTorreOpportunity(o, fallbackCompany);
      if (!normalized || seen.has(normalized.url)) continue;
      seen.add(normalized.url);
      out.push(normalized);
    }
    return out;
  },
};

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Read the keys printed in the message — they identify what came back (e.g. {error, message} points to an auth/quota problem).
  2. Retry after a delay; transient 429/5xx responses often arrive as malformed bodies.
  3. Verify API credentials, endpoint URL, and required headers for the Torre provider are current.
  4. Check for proxy/WAF interference on your network if the body is an HTML/challenge payload.
  5. If the envelope changed upstream, update the response parsing in providers/torre.mjs fetch() to the new schema.
Defensive patterns

Strategy: type-guard

Type guard

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

Try / catch

try {
  const jobs = await torreProvider.fetch(entry, ctx);
} catch (err) {
  if (String(err.message).startsWith('torre: unexpected API response')) {
    console.warn('Torre search returned an unexpected body:', err.message);
    // inspect keys in message; back off and retry, or check credentials
  } else throw err;
}

Prevention

When it happens

Trigger: The Torre search POST returns a non-standard body: an auth/quota error object, an empty 204/empty-body response, a WAF/Cloudflare challenge page parsed as JSON, or an upstream schema change moving results into a nested field.

Common situations: Torre API outage or rate limiting; invalid/missing API credentials surfacing as an error-shaped JSON body; corporate proxy replacing responses; Torre changing its search response envelope after an API version bump.

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@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/dcc07ffb5a768110. Report an issue: GitHub.