{"record":{"id":"77610c5b9647ed01","repo":"santifer/career-ops","slug":"nofluffjobs-careers-url-or-api-must-be-a-trusted","errorCode":null,"errorMessage":"nofluffjobs: careers_url or api must be a trusted nofluffjobs.com URL","messagePattern":"nofluffjobs: careers_url or api must be a trusted nofluffjobs\\.com URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/nofluffjobs.mjs","lineNumber":138,"sourceCode":"        url: `${JOB_BASE}${slug}`,\n        company,\n        location: normalizeLocation(posting),\n        postedAt: postedAtMillis(posting.posted),\n      };\n    })\n    .filter(Boolean);\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'nofluffjobs',\n\n  detect(entry) {\n    return detectUrl(entry);\n  },\n\n  async fetch(entry, ctx) {\n    if (!detectUrl(entry)) throw new Error('nofluffjobs: careers_url or api must be a trusted nofluffjobs.com URL');\n\n    const maxPages = Number(entry.max_pages || MAX_PAGES);\n    const jobs = [];\n    const seen = new Set();\n\n    for (let pageTo = 1; pageTo <= maxPages; pageTo++) {\n      const { url, body } = buildRequest(entry, pageTo);\n      const json = await ctx.fetchJson(url, {\n        method: 'POST',\n        body: JSON.stringify(body),\n        headers: {\n          accept: 'application/json, text/plain, */*',\n          'content-type': 'application/infiniteSearch+json',\n        },\n        redirect: 'error',\n      });\n      for (const job of parseNoFluffJobsResponse(json)) {\n        if (seen.has(job.url)) continue;","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/nofluffjobs.mjs#L120-L156","documentation":"The nofluffjobs provider's fetch() first runs detectUrl(entry) to confirm the entry actually points at a trusted nofluffjobs.com URL (careers_url or api). If detection fails — no URL configured, or one that fails the assert — fetch throws this error instead of attempting a request. It signals a configuration problem, not a network problem.","triggerScenarios":"Calling the provider's fetch() with an entry that has neither careers_url nor api set, has them empty, or has values that fail assertNoFluffUrl (wrong host or non-https).","commonSituations":"A portals.yml entry missing the url/api fields; the entry was intended for a different provider (Greenhouse/Lever) and has no NoFluffJobs URL; field name typo ('career_url' instead of 'careers_url'); URL set to another domain.","solutions":["Add a valid https:// nofluffjobs.com careers_url or api field to the entry in portals.yml","Fix the field-name typo so detectUrl can find the URL (careers_url / api)","If the company is not on NoFluffJobs, route the entry to the correct provider instead","Run detect() on the entry first if you need to conditionally dispatch to this provider"],"exampleFix":"// before\n{ company: 'Acme' } // no url -> fetch throws\n// after\n{ company: 'Acme', careers_url: 'https://nofluffjobs.com/api/search/posting' }","handlingStrategy":"validation","validationCode":"if (!nofluffjobs.detect(entry)) {\n  throw new Error(`${entry.company}: no nofluffjobs careers_url/api configured`);\n}\nawait nofluffjobs.fetch(entry, ctx);","typeGuard":"function hasTrustedNoFluffUrl(entry) {\n  const u = entry.api || entry.careers_url || '';\n  try {\n    const p = new URL(u);\n    return p.protocol === 'https:' && p.hostname.endsWith('nofluffjobs.com');\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  await nofluffjobs.fetch(entry, ctx);\n} catch (e) {\n  if (String(e.message).includes('must be a trusted nofluffjobs.com URL')) {\n    log.warn(`${entry.company} is not configured for nofluffjobs; dispatch to another provider`);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Call detect() before fetch() when dispatching entries across providers dynamically","Spell config field names exactly (careers_url, api) — typos silently read as missing","Run audit-portals.mjs to find entries with no provider claiming them","Give every portals.yml entry an explicit provider-appropriate URL"],"tags":["config","url-validation","provider-routing"],"backgroundTag":"invalid-config-value","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"}