{"record":{"id":"0c5d09d68b1c4aac","repo":"santifer/career-ops","slug":"portals-file-not-found-filepath","errorCode":null,"errorMessage":"portals file not found: ${filePath}","messagePattern":"portals file not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"audit-portals.mjs","lineNumber":316,"sourceCode":"    // exactly the way scan.mjs does.\n    const resolved = providers && providers.size > 0 ? resolveProvider(entry, providers) : null;\n    if (resolved?.provider) continue;\n    const row = {\n      name: entry.name,\n      scanMethod: entry.scan_method || null,\n      careers_url: typeof entry.careers_url === 'string' ? entry.careers_url : '',\n      error: resolved?.error || null,\n    };\n    if (row.error) unknownProvider.push(row);\n    else if (row.scanMethod) handoff.push(row);\n    else silent.push(row);\n  }\n  return { silent, handoff, unknownProvider };\n}\n\n/** Read tracked_companies out of a portals file. Throws on a missing file. */\nexport function loadCompanies(filePath = DEFAULT_PORTALS_PATH) {\n  if (!existsSync(filePath)) throw new Error(`portals file not found: ${filePath}`);\n  const cfg = yaml.load(readFileSync(filePath, 'utf-8')) || {};\n  return Array.isArray(cfg.tracked_companies) ? cfg.tracked_companies : [];\n}\n\nconst ICON = { ok: '✅', small: '🟡', empty: '⚪', 'no-provider': '🚨', error: '❌' };\n\nconst KNOWN_FLAGS = [\n  '--summary', '--json', '--strict', '--company', '--file',\n  '--baseline', '--small-threshold', '--help', '-h',\n];\nconst VALUE_FLAGS = ['--company', '--file', '--baseline', '--small-threshold'];\n\nconst USAGE = `Usage:\n  node audit-portals.mjs                       # audit every enabled company\n  node audit-portals.mjs --summary             # one line per company\n  node audit-portals.mjs --json                # machine-readable, for --baseline\n  node audit-portals.mjs --company Adyen       # audit a single company\n  node audit-portals.mjs --file <path>         # use a specific portals file","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/santifer/career-ops/blob/e7abd431fce9348a95261acac9e0c14779c35df8/audit-portals.mjs#L298-L334","documentation":"audit-portals.mjs's loadCompanies() reads tracked_companies from a portals YAML file and throws when the file does not exist on disk. The audit cannot run without portal configuration, so the library fails immediately with the exact path it looked for, rather than silently auditing zero companies.","triggerScenarios":"Running `node audit-portals.mjs` before portals.yml has been created (repo not onboarded); passing --portals with a typo'd or wrong path; running from a working directory where the default DEFAULT_PORTALS_PATH resolves elsewhere; the file having been renamed, moved, or gitignored-and-never-restored on a fresh clone.","commonSituations":"Fresh clone of career-ops where templates/portals.example.yml was never copied to portals.yml; typos like `--portals portal.yml`; running the script from a different directory with a relative --portals path; CAREER_OPS_ROOT pointing at the wrong tree so the default path resolves to a nonexistent location.","solutions":["Create the portals file: copy templates/portals.example.yml to portals.yml in the repo root (or run the career-ops onboarding that does it).","If using --portals, verify the exact path exists: `ls <path>` — check for typos and pass an absolute path when not at repo root.","Run the command from the repository root so the default DEFAULT_PORTALS_PATH resolves.","If a custom data root is intended, set CAREER_OPS_ROOT/CAREER_OPS_DATA_DIR to the tree that actually contains the portals file."],"exampleFix":"// before (fresh clone, no portals.yml)\nnode audit-portals.mjs\n// Error: portals file not found: portals.yml\n// after\ncp templates/portals.example.yml portals.yml\nnode audit-portals.mjs","handlingStrategy":"validation","validationCode":"import { existsSync } from 'node:fs';\nconst portalsPath = process.env.CAREER_OPS_PORTALS ?? 'portals.yml';\nif (!existsSync(portalsPath)) {\n  console.error(`Create ${portalsPath} first: cp templates/portals.example.yml portals.yml`);\n  process.exit(1);\n}","typeGuard":"const portalsFileExists = (p) => { try { return existsSync(p) && statSync(p).isFile(); } catch { return false; } };","tryCatchPattern":"try {\n  const companies = loadCompanies(portalsPath);\n} catch (err) {\n  if (err.message.startsWith('portals file not found:')) {\n    const path = err.message.replace('portals file not found: ', '');\n    console.error(`No portals config at ${path}. Copy templates/portals.example.yml there or fix --portals.`);\n  } else throw err;\n}","preventionTips":["Complete career-ops onboarding (portals.yml) before running audit/scan tooling.","Run scripts from the repository root, or pass absolute --portals paths.","Double-check --portals spelling and that the file was not renamed or left un-restored after a clone.","Verify a custom CAREER_OPS_ROOT actually contains the portals file."],"tags":["config","file-not-found","yaml"],"backgroundTag":"config-file-not-found","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"}