{"record":{"id":"b2729b4610d17ea1","repo":"santifer/career-ops","slug":"apify-run-runid-returned-non-array-dataset-payl","errorCode":null,"errorMessage":"Apify run ${runId} returned non-array dataset payload","messagePattern":"Apify run (.+?) returned non-array dataset payload","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/apify/_apify.mjs","lineNumber":182,"sourceCode":"    if (sleepMs > 0) await sleep(sleepMs);\n  }\n  // Fire-and-forget cleanup; don't add abortRun's 5s to our wall-clock budget.\n  void abortRun(runId, token).catch(() => {});\n  const suffix = lastError ? ` (last error: ${lastError.message})` : '';\n  throw new Error(`Apify run ${runId} did not finish within ${Math.round(timeoutMs / 1000)}s${suffix}`);\n}\n\nasync function fetchDatasetItems(runId, token, deadline = null) {\n  const url = `${APIFY_API_BASE}/actor-runs/${runId}/dataset/items`;\n  const items = await fetchJson(\n    url,\n    { headers: authHeaders(token) },\n    PER_REQUEST_TIMEOUT_MS * 2,\n    CONNECT_RETRY_ATTEMPTS,\n    deadline,\n  );\n  if (!Array.isArray(items)) {\n    throw new Error(`Apify run ${runId} returned non-array dataset payload`);\n  }\n  return items;\n}\n\nexport async function runActor(actorId, input, { timeoutMs = DEFAULT_RUN_TIMEOUT_MS, token = process.env.APIFY_TOKEN } = {}) {\n  if (!token) throw new Error('APIFY_TOKEN not set');\n  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n    throw new Error(`apify: invalid timeoutMs ${JSON.stringify(timeoutMs)} (must be a positive finite number of milliseconds)`);\n  }\n  // Single deadline shared across startRun → waitForRun → fetchDatasetItems so\n  // the caller's timeoutMs is the end-to-end ceiling, not just the wait loop.\n  const deadline = Date.now() + timeoutMs;\n  const runId = await startRun(actorId, input, token, deadline);\n  const run = await waitForRun(runId, token, deadline, timeoutMs);\n  if (run.status !== 'SUCCEEDED') {\n    const reason = run.statusMessage ? `: ${run.statusMessage}` : '';\n    throw new Error(`Apify actor ${actorId} finished with status ${run.status}${reason}`);\n  }","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/plugins/apify/_apify.mjs#L164-L200","documentation":"Thrown by `fetchDatasetItems` (plugins/apify/_apify.mjs:182) when the GET to `/actor-runs/<runId>/dataset/items` returns a payload that is not a JSON array. Apify's dataset endpoint is expected to return a bare JSON array of item objects; a non-array (object envelope, paginated wrapper, empty object, or error body) means the result cannot be consumed as items, so it fails rather than silently treating it as zero results.","triggerScenarios":"After a SUCCEEDED run, the dataset fetch returns something like `{ data: [...] }` (envelope), a paginated object, or an error JSON object. `Array.isArray(items)` is false, so the guard throws.","commonSituations":"Apify API version drift returning an envelope instead of a bare array; a dataset endpoint change to pagination by default; an intercepting proxy/captive portal returning a JSON error object; the run's dataset being empty but returned as `{}` instead of `[]`.","solutions":["Inspect the actor run on the Apify console — confirm the dataset actually has items and the expected shape.","Check for Apify v2 API changes to the dataset/items endpoint (envelope vs bare array).","Retry once; if a proxy is intercepting, bypass it for api.apify.com.","If the API schema changed, update fetchDatasetItems to unwrap the envelope."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const items = await runActor(actorId, input, opts);\n} catch (err) {\n  if (/non-array dataset payload/.test(err.message)) {\n    console.error(`Apify dataset shape changed for ${actorId} — possible API drift. ${err.message}`);\n    // do not blindly coerce; investigate the actual payload\n  } else throw err;\n}","preventionTips":["Keep the apify plugin updated to track dataset endpoint schema.","Bypass intercepting proxies for api.apify.com to avoid captive-portal JSON."],"tags":["apify","api","response-shape","dataset"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}