{"record":{"id":"8946eac71a1e4a11","repo":"santifer/career-ops","slug":"local-parser-json-must-be-an-array-or-contain-jobs","errorCode":null,"errorMessage":"local parser JSON must be an array or contain jobs[]/results[]","messagePattern":"local parser JSON must be an array or contain jobs\\[\\]/results\\[\\]","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/local-parser.mjs","lineNumber":182,"sourceCode":"  // cwd is pinned to the project root so a relative script arg resolves to the\n  // same file resolveInvocation() validated, regardless of the caller's cwd.\n  const { stdout } = await execFileAsync(command, args, {\n    cwd: PROJECT_ROOT,\n    timeout,\n    maxBuffer,\n    windowsHide: true,\n  });\n\n  let payload;\n  try {\n    payload = JSON.parse(stdout);\n  } catch {\n    throw new Error('local parser returned invalid JSON');\n  }\n\n  const rawJobs = Array.isArray(payload) ? payload : payload.jobs || payload.results;\n  if (!Array.isArray(rawJobs)) {\n    throw new Error('local parser JSON must be an array or contain jobs[]/results[]');\n  }\n\n  return rawJobs\n    .map(job => normalizeParserJob(job, entry))\n    .filter(Boolean);\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'local-parser',\n\n  detect(entry) {\n    if (!entry.parser?.command) return null;\n\n    // An invocation we can't safely resolve (unknown command, out-of-repo or\n    // missing script, inline-code flags) is not runnable — skip it.\n    try {\n      resolveInvocation(entry);","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/local-parser.mjs#L164-L200","documentation":"JSON.parse succeeded but the parsed value is neither an array nor an object containing a jobs or results array. The provider accepts a bare array (payload) or an envelope ({jobs:[...]} or {results:[...]}); anything else is rejected so the downstream .map() always receives an array.","triggerScenarios":"The parser emitted valid JSON of an unexpected shape: a single job object {}, an object whose list lives under a different key (e.g. {offers:[...]}), a scalar (string/number), or {jobs: {not: 'an array'}}.","commonSituations":"The parser's output key isn't 'jobs' or 'results'; the parser returns one job object instead of a list; the parser schema changed and the array was renamed; a wrapper object was added around the list.","solutions":["Inspect the parsed payload (log it) to see the actual structure.","Make the parser emit a bare top-level array, or wrap the list under {jobs: [...]} / {results: [...]}.","If the existing key is different (e.g. 'offers'), change the parser to rename it to 'jobs', or extend the provider's rawJobs extraction line."],"exampleFix":"# before (parser stdout)\n{\"offers\": [{\"title\": \"Dev\"}]}\n\n# after (parser renamed the key)\n{\"jobs\": [{\"title\": \"Dev\"}]}","handlingStrategy":"type-guard","validationCode":"// Confirm the parser output contract: array, or object with jobs[]/results[].\nfunction conformsToParserContract(payload) {\n  if (Array.isArray(payload)) return true;\n  if (payload && typeof payload === 'object') return Array.isArray(payload.jobs) || Array.isArray(payload.results);\n  return false;\n}","typeGuard":"/** @param {unknown} payload */\nfunction isParserJobList(payload) {\n  if (Array.isArray(payload)) return true;\n  if (payload && typeof payload === 'object') {\n    const o = /** @type {any} */ (payload);\n    return Array.isArray(o.jobs) || Array.isArray(o.results);\n  }\n  return false;\n}","tryCatchPattern":"try {\n  const jobs = await provider.fetch(entry, ctx);\n  results.push(...jobs);\n} catch (err) {\n  if (err.message.includes('must be an array or contain jobs[]/results[]')) {\n    console.warn(`parser ${entry.name} returned an unexpected JSON shape — emit a bare array or {jobs:[]}/{results:[]}`);\n  }\n  throw err;\n}","preventionTips":["Standardize every local parser to emit a bare top-level JSON array.","If you need an envelope, use exactly the key 'jobs' or 'results'.","Add a parser-output schema check in CI by running each parser against a fixture and validating the shape."],"tags":["json","response-shape","local-parser","parser-output","api-contract"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}