{"record":{"id":"407618a0f1e53401","repo":"santifer/career-ops","slug":"jibeapply-careers-url-required","errorCode":null,"errorMessage":"jibeapply: careers_url required","messagePattern":"jibeapply: careers_url required","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/jibeapply.mjs","lineNumber":92,"sourceCode":"    })\n    .filter(Boolean);\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'jibeapply',\n\n  detect(entry) {\n    const url = entry.careers_url;\n    if (typeof url !== 'string') return null;\n    const apiUrl = toApiUrl(url);\n    if (!apiUrl) return null;\n    return { url: apiUrl };\n  },\n\n  async fetch(entry, ctx) {\n    const url = entry.careers_url;\n    if (typeof url !== 'string' || !url) throw new Error('jibeapply: careers_url required');\n\n    // Prefer an explicit entry.api (allows iCIMS-hosted, branded JibeApply sites\n    // that share the same JSON schema but aren't on jibeapply.com).\n    const apiUrl = (typeof entry.api === 'string' && validateExplicitApi(entry.api))\n      || toApiUrl(url);\n    if (!apiUrl) throw new Error(`jibeapply: cannot derive API URL for ${entry.name}`);\n    const first = await ctx.fetchJson(apiUrl, { redirect: 'error' });\n    const total = first.totalCount ?? 0;\n    // Use the actual number of items returned as page size — some implementations\n    // set `count` to the total rather than the per-page count.\n    const pageSize = first.jobs?.length || first.count || DEFAULT_PAGE_SIZE;\n    const allJobs = [...(first.jobs ?? [])];\n\n    if (total > pageSize && pageSize > 0) {\n      const maxPages = resolveMaxPages(entry);\n      const pages = Math.min(Math.ceil(total / pageSize), maxPages);\n      // Sequential, not concurrent (mirrors providers/4dayweek.mjs, thehub.mjs,\n      // arbeitnow.mjs, workday.mjs) — a single tenant's API has no reason to","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/jibeapply.mjs#L74-L110","documentation":"Thrown by jibeapply fetch() when entry.careers_url is not a non-empty string. careers_url is the one field the JibeApply provider unconditionally requires (detect() also returns null without it). fetch() checks this before attempting any URL derivation, so a missing/blank/non-string careers_url fails fast with a clear message rather than a downstream null deref.","triggerScenarios":"An entry explicitly tagged provider: jibeapply but with no careers_url key, an empty careers_url: '', or careers_url set to a non-string YAML value (number/bool). The provider was routed explicitly (bypassing detect) but the required field was omitted.","commonSituations":"Setting provider: jibeapply without supplying careers_url (the explicit-provider path skips detect's guard); YAML indentation putting careers_url under a nested block so it is undefined at the entry level; a templating step that blanked the field.","solutions":["Add a non-empty careers_url string to the entry, ideally the https://<slug>.jibeapply.com form.","If you intended to drive JibeApply purely via entry.api (iCIMS-hosted branded site), note that fetch() still requires careers_url to be a non-empty string — supply it even if api is the real source.","Validate entries before scan: assert every provider: jibeapply row has a string careers_url."],"exampleFix":"# before\n- name: Acme\n  provider: jibeapply\n  api: https://careers.acme.com/api/jobs\n\n# after\n- name: Acme\n  provider: jibeapply\n  careers_url: https://acme.jibeapply.com\n  api: https://careers.acme.com/api/jobs","handlingStrategy":"validation","validationCode":"// Enforce the required field before driving the provider.\nif (typeof entry.careers_url !== 'string' || !entry.careers_url) {\n  throw new Error(`jibeapply: ${entry.name} is missing the required careers_url string`);\n}","typeGuard":"/** Entry has the non-empty string careers_url the JibeApply provider requires. */\nfunction hasJibeapplyCareersUrl(entry) {\n  return !!entry && typeof entry === 'object'\n    && typeof entry.careers_url === 'string' && entry.careers_url.length > 0;\n}","tryCatchPattern":"try {\n  const jobs = await jibeapplyProvider.fetch(entry, ctx);\n} catch (err) {\n  if (/careers_url required/.test(err.message)) {\n    console.error(`config: ${entry.name} — jibeapply needs a non-empty careers_url string`);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Always supply a non-empty careers_url string for provider: jibeapply, even when driving via entry.api.","Lint portal entries to flag any provider: jibeapply row missing careers_url.","Remember the explicit-provider path bypasses detect()'s guard, so fetch()'s check is the only gate."],"tags":["config","required-field","jibeapply","ats"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}