{"record":{"id":"a5486b8dc7bbb357","repo":"santifer/career-ops","slug":"arbeitsagentur-all-keywords-length-keyword-req","errorCode":null,"errorMessage":"arbeitsagentur: all ${keywords.length} keyword request(s) failed — ${errors[0]}","messagePattern":"arbeitsagentur: all (.+?) keyword request\\(s\\) failed — (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"providers/arbeitsagentur.mjs","lineNumber":260,"sourceCode":"        wide\n          .map(normalizeJob)\n          .filter(Boolean)\n          .filter(job => !byRef.has(job.refnr))\n          .map(job => [job.refnr, job]),\n      ).values()];\n      for (const job of wideJobs) {\n        if (remoteMatch !== 'filter' || REMOTE_RE.test(job.title)) {\n          job.location = job.location ? `${job.location} · Deutschlandweit (Homeoffice)` : 'Deutschlandweit (Homeoffice)';\n        }\n        if (!byRef.has(job.refnr)) byRef.set(job.refnr, job);\n      }\n    }\n\n    // Total outage = every primary request failed. A keyword that answered with\n    // zero results is not an outage, so key off the success count, not the\n    // deduped result size — otherwise a legitimately-empty search throws.\n    if (succeeded === 0 && errors.length) {\n      throw new Error(`arbeitsagentur: all ${keywords.length} keyword request(s) failed — ${errors[0]}`);\n    }\n\n    return [...byRef.values()].map(({ refnr, ...job }) => job);\n  },\n};\n","sourceCodeStart":242,"sourceCodeEnd":266,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/arbeitsagentur.mjs#L242-L266","documentation":"After running one request per keyword, the provider distinguishes 'zero results' (legitimate) from 'zero successful requests' (outage). If every keyword request failed and at least one error was recorded, it throws summarizing the count and the first error — a total outage of the Bundesagentur für Arbeit search endpoint, not an empty labor market.","triggerScenarios":"All primary keyword requests to the arbeitsagentur APIs failed — endpoint down or redesigned, network/TLS blocked from the host, every request rate-limited or session-token rejected, or a systemic parameter error (e.g. invalid umkreis/size) that fails identically for each keyword.","commonSituations":"The arbeitsagentur API has an outage or maintenance window; corporate proxy/firewall blocks the host; the API started rejecting the provider's parameter combination after an update; sustained 429s during a large sweep where every keyword hit the throttle.","solutions":["Read errors[0] in the message to classify: network/DNS => check connectivity/proxy; 4xx parameter => re-check parseArbeitsagenturConfig outputs against the current API; 429/5xx => retry with backoff later.","Test one keyword manually with curl replicating the was/wo/umkreis params to see the raw failure.","If the endpoint was redesigned, update fetchKeyword's parameter building and response parsing in providers/arbeitsagentur.mjs.","Retry the scan after a backoff window — transient outages throw this on the whole entry but recover on a later run."],"exampleFix":"// caller-side: retry the whole entry once on total outage before surfacing\ntry {\n  jobs = await arbeitsagentur.fetch(entry, ctx);\n} catch (err) {\n  if (/all \\d+ keyword request\\(s\\) failed/.test(err.message) && isTransient(err)) {\n    await sleep(60_000);\n    jobs = await arbeitsagentur.fetch(entry, ctx);\n  } else throw err;\n}","handlingStrategy":"retry","validationCode":"// pre-flight: one cheap request to see if the endpoint answers at all\nconst probe = await fetch('https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/jobs?was=test&angebotsart=4', { headers: { accept: 'application/json' } });\nif (!probe.ok) throw new Error(`arbeitsagentur endpoint unhealthy pre-scan: HTTP ${probe.status}`);","typeGuard":"function isTotalOutage(err) {\n  return /all \\d+ keyword request\\(s\\) failed/.test(String(err?.message));\n}","tryCatchPattern":"try {\n  jobs = await provider.fetch(entry, ctx);\n} catch (err) {\n  if (isTotalOutage(err) && attempt < 2) {\n    await new Promise(r => setTimeout(r, 60_000 * (attempt + 1)));\n    return fetchEntryWithRetry(entry, ctx, attempt + 1);\n  }\n  throw err;\n}","preventionTips":["Schedule scans outside known maintenance windows and accept that arbeitsagentur outages recover on retry.","Read errors[0] in the message first: transient (5xx/timeout) vs systemic (4xx parameter/auth) needs different fixes.","Check corporate proxy/firewall reachability to the arbeitsagentur hosts before blaming the API.","Keep per-keyword successes count (not result count) as the outage signal — empty results are legitimate."],"tags":["network","api","outage","provider"],"backgroundTag":"api-request-failed","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}