{"record":{"id":"d6e36be653224ac1","repo":"santifer/career-ops","slug":"avature-cannot-resolve-origin-for-entry-name","errorCode":null,"errorMessage":"avature: cannot resolve origin for ${entry.name}","messagePattern":"avature: cannot resolve origin for (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"providers/avature.mjs","lineNumber":185,"sourceCode":"/** @type {Provider} */\nexport default {\n  id: 'avature',\n\n  detect(entry) {\n    const url = entry.api || entry.careers_url || '';\n    if (typeof url !== 'string') return null;\n    try {\n      const host = new URL(url).host.toLowerCase();\n      if (host === 'avature.net' || host.endsWith('.avature.net')) return { url };\n    } catch {\n      /* not absolute */\n    }\n    return null;\n  },\n\n  async fetch(entry, ctx) {\n    const cfg = resolveConfig(entry);\n    if (!cfg) throw new Error(`avature: cannot resolve origin for ${entry.name}`);\n    const maxPages = Math.min(\n      HARD_MAX_PAGES,\n      Number.isFinite(entry.max_pages) && entry.max_pages > 0 ? Number(entry.max_pages) : DEFAULT_MAX_PAGES,\n    );\n\n    // Pagination key. An explicit `offset_param` pins it (and disables the\n    // auto-switch below); otherwise start with `jobOffset` and self-heal. A\n    // non-string/empty override falls back to the default so a malformed entry\n    // can't produce `?=N`.\n    const pinned = typeof entry.offset_param === 'string' && entry.offset_param.trim();\n    let offsetParam = pinned ? entry.offset_param.trim() : PRIMARY_OFFSET_PARAM;\n    let canHeal = !pinned; // once the key is pinned, never auto-switch\n\n    const jobs = [];\n    const seen = new Set();\n\n    const getPage = async (param, page) => {\n      const usp = new URLSearchParams(cfg.extraParams);","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/santifer/career-ops/blob/e7abd431fce9348a95261acac9e0c14779c35df8/providers/avature.mjs#L167-L203","documentation":"The Avature provider's fetch() calls resolveConfig(entry); when it returns null the provider cannot determine which Avature origin/instance to query, so it throws. Avature boards are self-hosted per customer, so the entry must supply enough info (an api URL or a recognizable origin) to build the search endpoint.","triggerScenarios":"Calling fetch(entry) with an entry that has no `api` URL and no URL resolveConfig can map to an Avature origin — e.g. only a generic careers page, or an api URL on a domain resolveConfig does not recognize.","commonSituations":"portals.yml entry listing a company's own careers site with a note 'powered by Avature' but no API endpoint; tenant URL changed after a company migrated; config copied from another provider type.","solutions":["Add the entry's explicit `api:` URL pointing at the company's Avature endpoint (their real Avature search URL).","Discover the actual Avature endpoint by inspecting network requests on the company's careers page and copy the search API URL into the config.","If the company is not on Avature anymore, reassign the entry to the correct provider.","Fail fast at config validation: run resolveConfig over all entries up front and report which ones cannot resolve."],"exampleFix":"// before\n{ name: 'ExampleCo', careers_url: 'https://exampleco.com/jobs' }\n// fetch throws: cannot resolve origin\n\n// after\n{ name: 'ExampleCo', api: 'https://exampleco.avature.net/api/search' }","handlingStrategy":"fallback","validationCode":"function hasAvatureOrigin(entry) {\n  return resolveConfig(entry) != null;\n}","typeGuard":"function isAvatureReadyEntry(entry) {\n  const cfg = entry ? resolveConfig(entry) : null;\n  return cfg != null && typeof cfg.origin === 'string' && cfg.origin.startsWith('https://');\n}","tryCatchPattern":"try {\n  return await avatureProvider.fetch(entry, ctx);\n} catch (err) {\n  if (/cannot resolve origin/.test(err.message)) {\n    console.warn(`Entry ${entry.name}: add an explicit Avature api URL to portals.yml`);\n    return null;\n  }\n  throw err;\n}","preventionTips":["Capture the real Avature search endpoint from the board's network requests before configuring the entry.","Re-verify origins after companies change ATS vendors.","Run a startup pass that resolves config for every Avature entry and reports failures.","Keep provider types consistent — don't reuse Greenhouse-shaped entries for Avature boards."],"tags":["config","avature","provider","origin"],"backgroundTag":"missing-config-value","analyzedSha":"e7abd431fce9348a95261acac9e0c14779c35df8","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}