{"record":{"id":"662cfe7129d0571a","repo":"santifer/career-ops","slug":"jobbankca-entry-entry-name-unnamed-h","errorCode":null,"errorMessage":"jobbankca: entry \"${entry?.name || '(unnamed)'}\" has no jobbankca.keywords[] and no config/profile.yml target_roles to fall back to","messagePattern":"jobbankca: entry \"(.+?)\" has no jobbankca\\.keywords\\[\\] and no config/profile\\.yml target_roles to fall back to","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/jobbankca.mjs","lineNumber":248,"sourceCode":"}\n\n/** @type {Provider} */\nexport default {\n  id: 'jobbankca',\n\n  detect(entry) {\n    return entry?.provider === 'jobbankca' ? { url: FEED_URL } : null;\n  },\n\n  async fetch(entry, ctx) {\n    let { keywords } = parseJobBankConfig(entry);\n    // Fall back to config/profile.yml's target_roles when this entry has no\n    // jobbankca.keywords[] of its own — same convention vdab.mjs uses, so a\n    // user who already onboarded with target roles doesn't have to duplicate\n    // them into every keyword-required provider's config by hand.\n    if (!keywords.length) keywords = resolveProfileKeywords();\n    if (!keywords.length) {\n      throw new Error(`jobbankca: entry \"${entry?.name || '(unnamed)'}\" has no jobbankca.keywords[] and no config/profile.yml target_roles to fall back to`);\n    }\n\n    const entryMaxPages = Number.isInteger(entry?.max_pages) && entry.max_pages > 0\n      ? Math.min(entry.max_pages, MAX_PAGES_CAP)\n      : DEFAULT_MAX_PAGES;\n    const maxPages = Math.min(\n      entryMaxPages,\n      Number.isInteger(ctx?.maxPages) && ctx.maxPages > 0 ? ctx.maxPages : Infinity,\n    );\n\n    /** @type {Map<string, {title: string, url: string, company: string, location: string, postedAt?: number}>} */\n    const byUrl = new Map();\n    const errors = [];\n    let succeeded = 0;\n\n    for (const keyword of keywords) {\n      let keywordFailed = false;\n      for (let page = 1; page <= maxPages; page++) {","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/santifer/career-ops/blob/1696bec4d021768e7359f9aad6b329cba883da20/providers/jobbankca.mjs#L230-L266","documentation":"fetch() requires a keyword list to build jobbankca search requests. It takes the entry's own jobbankca.keywords[], else falls back to target_roles in config/profile.yml; if both are empty it throws. The library refuses to issue a query-less fetch because Job Bank searches are keyword-driven.","triggerScenarios":"Running a scan/pipeline with a portals.yml jobbankca entry lacking jobbankca.keywords[], while config/profile.yml has no target_roles (or an empty list) — usually a freshly onboarded or template profile.","commonSituations":"New user skipped personalization of config/profile.yml; entry name present but keywords key misspelled (e.g. keyword: vs keywords:); target_roles defined under the wrong YAML nesting level; entry?.name undefined shows '(unnamed)' indicating a malformed entry object.","solutions":["Add jobbankca.keywords: [...] to the jobbankca entry in portals.yml","Or set target_roles in config/profile.yml so the provider can fall back to it","Verify YAML key spelling/nesting: keywords must be exactly jobbankca.keywords[] under the entry","Check that your config loader actually resolves profile.yml from the expected data root (CAREER_OPS_DATA_DIR)"],"exampleFix":"// before (portals.yml)\n- name: Job Bank CA\n  provider: jobbankca\n// after\n- name: Job Bank CA\n  provider: jobbankca\n  jobbankca:\n    keywords: [\"data engineer\", \"backend developer\"]","handlingStrategy":"validation","validationCode":"const entryKeywords = entry?.jobbankca?.keywords ?? [];\nconst profileRoles = profile?.target_roles ?? [];\nif (!entryKeywords.length && !profileRoles.length) {\n  throw new Error(`entry ${entry?.name}: no keywords and no target_roles fallback configured`);\n}","typeGuard":"function hasKeywords(entry) {\n  return Array.isArray(entry?.jobbankca?.keywords) && entry.jobbankca.keywords.length > 0;\n}","tryCatchPattern":"try {\n  await jobbankca.fetch(entry, ctx);\n} catch (e) {\n  if (e.message.includes('no jobbankca.keywords')) {\n    console.error(`Fix portals.yml entry \"${entry?.name}\": add jobbankca.keywords or set target_roles in config/profile.yml`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Set target_roles in config/profile.yml during onboarding — it doubles as the fallback for all keyword-required providers","Double-check YAML key spelling: jobbankca.keywords (plural, nested under the provider key)","Add a config linter that asserts keyword-required provider entries define keywords","If the entry reports '(unnamed)', the entry object itself is malformed — fix its structure first"],"tags":["config","missing-keywords","portals-yml","jobbankca"],"backgroundTag":"missing-config-key","analyzedSha":"1696bec4d021768e7359f9aad6b329cba883da20","analyzedAt":"2026-09-01T19:19:23.111Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}