santifer/career-ops · error · Error

agentic-jobs: parsed 0 jobs from the API — the response shap

Error message

agentic-jobs: parsed 0 jobs from the API — the response shape likely changed

What it means

After paginating through all agentic-jobs pages (respecting the MAX_JOBS=2000 and MAX_PAGES=40 caps), if zero jobs were collected the provider throws. The reasoning: a genuinely empty board is implausible for this feed, so parsing 0 jobs almost certainly means the per-record normalizer (normalizeAgenticJob) no longer matches the record shape — every record got normalized to null and was skipped. This is a 'parsed nothing' sentinel that distinguishes 'feed empty' (shouldn't happen) from 'we silently lost every job to a shape change'.

Source

Thrown at providers/agentic-jobs.mjs:193

      // Trust the API's own reported page size over our constant, in case it
      // ever differs from the documented default.
      const effectivePageSize = typeof json.meta?.per_page === 'number' && json.meta.per_page > 0 ? json.meta.per_page : PAGE_SIZE;

      for (const record of records) {
        const job = normalizeAgenticJob(record);
        if (job && !seen.has(job.url)) {
          seen.add(job.url);
          jobs.push(job);
        }
      }

      if (jobs.length >= MAX_JOBS) break;
      if (records.length < effectivePageSize) break; // short page — last one
      if (total !== null && page * effectivePageSize >= total) break;
    }

    if (jobs.length === 0) {
      throw new Error('agentic-jobs: parsed 0 jobs from the API — the response shape likely changed');
    }
    return jobs.slice(0, MAX_JOBS);
  },
};

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Inspect normalizeAgenticJob in providers/agentic-jobs.mjs to see which fields it requires and how it returns null when they're missing.
  2. Reproduce with `curl '<API_BASE>/jobs?page=1'` and compare a real record's keys against the normalizer's expected fields.
  3. If the record layout changed (e.g. fields nested under attributes), update normalizeAgenticJob to read from the new shape.
  4. If a required field was renamed, update the field access in the normalizer.
  5. Run the provider's tests after the change.

Example fix

// Example: upstream wrapped job fields under `attributes` (JSON:API style)
// before
function normalizeAgenticJob(record) {
  const url = record?.url;
  const title = record?.title;
  if (!url || !title) return null;
  ...
}

// after
function normalizeAgenticJob(record) {
  const a = record?.attributes ?? record; // tolerate both shapes
  const url = a?.url;
  const title = a?.title;
  if (!url || !title) return null;
  ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check the normalizer against a sample record before a full sweep.
const sample = await ctx.fetchJson(`${API_BASE}/jobs?page=1`);
const first = sample?.data?.[0];
const normalized = normalizeAgenticJob(first);
if (!normalized) {
  throw new Error('agentic-jobs normalizer rejects sample record — field shape likely changed; aborting sweep.');

Type guard

/** @param {unknown} j @returns {j is { url: string, title: string, company?: string, location?: string } | null} */
function isNormalizedJob(j) {
  if (!j || typeof j !== 'object') return false;
  const o = /** @type {any} */ (j);
  return typeof o.url === 'string' && typeof o.title === 'string';
}

Try / catch

try {
  const jobs = await provider.fetch(entry, ctx);
} catch (err) {
  if (/parsed 0 jobs/.test(String(err?.message))) {
    console.error('agentic-jobs: normalizer rejected every record. curl the API, compare record keys to normalizeAgenticJob, update it.');
  }
  throw err;
}

Prevention

When it happens

Trigger: The API returned well-formed `{data:[...]}` pages (so error 138 did not fire), but normalizeAgenticJob returned null for every record — typically because each record is missing required fields the normalizer checks (url, title, etc.), or the record's field layout changed so the normalizer's destructuring yields garbage. The total reached 0 across all pages.

Common situations: Upstream added a nesting level (e.g. job fields moved under a `attributes` sub-object, common in JSON:API); the `url` or `title` field was renamed, so the normalizer's required-field guard rejects every record; a localized/censored response dropped fields the normalizer requires.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/b0ff341f32145217. Report an issue: GitHub.