santifer/career-ops · error

arbeitsagentur: all keyword request(s) failed

Error message

arbeitsagentur: all ${keywords.length} keyword request(s) failed — ${errors[0]}

What it means

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.

Solutions

  1. 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.
  2. Test one keyword manually with curl replicating the was/wo/umkreis params to see the raw failure.
  3. If the endpoint was redesigned, update fetchKeyword's parameter building and response parsing in providers/arbeitsagentur.mjs.
  4. Retry the scan after a backoff window — transient outages throw this on the whole entry but recover on a later run.

Example fix

// caller-side: retry the whole entry once on total outage before surfacing
try {
  jobs = await arbeitsagentur.fetch(entry, ctx);
} catch (err) {
  if (/all \d+ keyword request\(s\) failed/.test(err.message) && isTransient(err)) {
    await sleep(60_000);
    jobs = await arbeitsagentur.fetch(entry, ctx);
  } else throw err;
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: one cheap request to see if the endpoint answers at all
const probe = await fetch('https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/jobs?was=test&angebotsart=4', { headers: { accept: 'application/json' } });
if (!probe.ok) throw new Error(`arbeitsagentur endpoint unhealthy pre-scan: HTTP ${probe.status}`);

Type guard

function isTotalOutage(err) {
  return /all \d+ keyword request\(s\) failed/.test(String(err?.message));
}

Try / catch

try {
  jobs = await provider.fetch(entry, ctx);
} catch (err) {
  if (isTotalOutage(err) && attempt < 2) {
    await new Promise(r => setTimeout(r, 60_000 * (attempt + 1)));
    return fetchEntryWithRetry(entry, ctx, attempt + 1);
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/a5486b8dc7bbb357. Report an issue: GitHub.

Appendix: source

Thrown at providers/arbeitsagentur.mjs:260

        wide
          .map(normalizeJob)
          .filter(Boolean)
          .filter(job => !byRef.has(job.refnr))
          .map(job => [job.refnr, job]),
      ).values()];
      for (const job of wideJobs) {
        if (remoteMatch !== 'filter' || REMOTE_RE.test(job.title)) {
          job.location = job.location ? `${job.location} · Deutschlandweit (Homeoffice)` : 'Deutschlandweit (Homeoffice)';
        }
        if (!byRef.has(job.refnr)) byRef.set(job.refnr, job);
      }
    }

    // Total outage = every primary request failed. A keyword that answered with
    // zero results is not an outage, so key off the success count, not the
    // deduped result size — otherwise a legitimately-empty search throws.
    if (succeeded === 0 && errors.length) {
      throw new Error(`arbeitsagentur: all ${keywords.length} keyword request(s) failed — ${errors[0]}`);
    }

    return [...byRef.values()].map(({ refnr, ...job }) => job);
  },
};

View on GitHub (pinned to aac998c7ed)