{"record":{"id":"cade3c5985fa0533","repo":"santifer/career-ops","slug":"tkms-cannot-resolve-jobs-host-for-entry-name","errorCode":null,"errorMessage":"tkms: cannot resolve jobs host for ${entry.name}","messagePattern":"tkms: cannot resolve jobs host for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/tkms.mjs","lineNumber":157,"sourceCode":"function resolveMaxPages(entry) {\n  const v = entry?.max_pages;\n  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES);\n  return MAX_PAGES;\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'tkms',\n\n  detect(entry) {\n    const url = entry.api || entry.careers_url || '';\n    if (typeof url !== 'string') return null;\n    return resolveConfig({ api: url }) ? { url } : null;\n  },\n\n  async fetch(entry, ctx) {\n    const cfg = resolveConfig(entry);\n    if (!cfg) throw new Error(`tkms: cannot resolve jobs host for ${entry.name}`);\n\n    const wait = (ms) => (ctx.sleep ? ctx.sleep(ms) : new Promise((r) => setTimeout(r, ms)));\n    const maxPages = resolveMaxPages(entry);\n    const jobs = [];\n    const seen = new Set();\n\n    for (let page = 0; page < maxPages; page++) {\n      if (page > 0) await wait(PAGE_DELAY_MS);\n      const json = await ctx.fetchJson(cfg.queryApi, {\n        method: 'POST',\n        redirect: 'error',\n        headers: { 'content-type': 'application/json', accept: 'application/json' },\n        body: JSON.stringify({ searchQuery: '', filter: {}, subclient: cfg.subclient, locale: cfg.locale, page }),\n      });\n      const { nextPage, rows } = parseQuery(json, cfg);\n      if (rows.length === 0) break;\n\n      let fresh = 0;","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/tkms.mjs#L139-L175","documentation":"The tkms provider resolves each portal entry to a concrete jobs-host configuration via resolveConfig(entry). When resolution returns null — the entry doesn't carry the URL fields resolveConfig needs — fetch() refuses to proceed. The provider only knows how to talk to a resolvable TKMS jobs host; it will not guess one from a name.","triggerScenarios":"fetch(entry, ctx) runs resolveConfig(entry) and gets null: the entry lacks a valid api/careers URL string (resolveConfig({ api: url }) fails) or the expected config fields are missing/mistyped, so it throws 'cannot resolve jobs host for <entry.name>'.","commonSituations":"A portals.yml entry for a TKMS company with no careers_url/api field; a URL typed with a typo that fails the resolver's validation; an entry using a field name the provider doesn't read (e.g. 'url' instead of 'api'); a company that migrated off TKMS so the host pattern no longer matches.","solutions":["Add or fix the api/careers URL on the entry so resolveConfig() succeeds — check providers/tkms.mjs for the exact expected shape.","Compare your entry against a known-good TKMS entry in portals.yml and copy its field layout.","Confirm the company still uses a TKMS jobs host by opening their careers page; if they migrated ATS, switch the entry to the matching provider.","Log resolveConfig(entry) inputs in a quick REPL to see which field is missing or malformed."],"exampleFix":"// before (portals.yml — no resolvable host)\n- name: SomeCompany\n  provider: tkms\n// after\n- name: SomeCompany\n  provider: tkms\n  careers_url: https://somecompany.com/api/jobs","handlingStrategy":"validation","validationCode":"function tkmsEntryIsConfigured(entry) {\n  const url = entry.api ?? entry.careers_url;\n  return typeof url === 'string' && /^https:\\/\\//.test(url);\n}\n// pre-flight: portals.filter(e => e.provider === 'tkms' && !tkmsEntryIsConfigured(e)) → fix config","typeGuard":"const hasResolvableTkmsHost = (entry) =>\n  entry != null\n  && typeof entry.api === 'string'\n  && entry.api.startsWith('https://');","tryCatchPattern":"try {\n  return await tkmsProvider.fetch(entry, ctx);\n} catch (err) {\n  if (String(err.message).startsWith('tkms: cannot resolve jobs host')) {\n    console.warn(`${entry.name}: missing/invalid TKMS api URL — fix portals.yml and re-run`);\n    return null;\n  }\n  throw err;\n}","preventionTips":["Copy the field layout from a known-good TKMS entry when adding new companies","Run a pre-flight config validation pass over portals.yml before scheduled scans","Re-check companies periodically — ATS migrations silently invalidate the host pattern","Name config fields exactly as the provider reads them (api/careers_url), not generic 'url'"],"tags":["config","tkms","provider","missing-url"],"backgroundTag":"missing-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"}