{"record":{"id":"874d5f096cee79e4","repo":"santifer/career-ops","slug":"portal-coverage-check-could-not-run-err-message","errorCode":null,"errorMessage":"Portal coverage check could not run: ${err.message}","messagePattern":"Portal coverage check could not run: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"verify-pipeline.mjs","lineNumber":579,"sourceCode":"    const malformed = entries.filter(e => e && e.enabled !== false && (typeof e.name !== 'string' || !e.name.trim()));\n    for (const e of malformed) {\n      warn(`portals.yml: an enabled entry has no name (careers_url: ${e.careers_url || 'none'}) — it cannot be provider-checked; give it a name`);\n    }\n\n    for (const e of unknownProvider) {\n      error(`portals.yml: \"${e.name}\" sets an unknown provider — ${e.error}. The entry never scans (see providers/ for valid ids)`);\n    }\n    for (const e of silent) {\n      warn(`portals.yml: \"${e.name}\" is enabled but no provider claims ${e.careers_url || 'its careers_url'} — scan.mjs skips it on every run without naming it (run node audit-portals.mjs)`);\n    }\n    if (silent.length === 0 && unknownProvider.length === 0 && malformed.length === 0) {\n      const enabled = entries.filter(e => e && e.enabled !== false).length;\n      ok(handoff.length > 0\n        ? `All ${enabled - handoff.length} scannable portals.yml entries resolve to a provider (${handoff.length} on websearch handoff)`\n        : `All ${enabled} enabled portals.yml entries resolve to a provider`);\n    }\n  } catch (err) {\n    warn(`Portal coverage check could not run: ${err.message}`);\n  }\n}\n\n// --- Check 16: invisible control bytes already in tracker cells (#3892) ---\n// cell() in tracker-utils.mjs strips these on the way in, which stops new ones\n// entering but can do nothing about the ones already written. This is the only\n// place such a byte is visible at all: it shifts or truncates the positional\n// `split('|')` parse, so a row silently reads as a different row or drops out\n// of a count entirely, while every renderer of the table — markdown, GitHub,\n// the web dashboard — shows the cell as correct. The corruption surfaces much\n// later as an unrelated arithmetic discrepancy with no trail back to the cause.\n//\n// Read off the RAW lines rather than the parsed `entries`, so a byte in a\n// column this file has no field for is caught too, and reported with the file\n// line number: a shifted parse is exactly the situation where the row's own #\n// cell is the thing not to trust.\n//\n// CONTROL_CHARS is imported, never re-declared — a second copy of the range","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/santifer/career-ops/blob/e7abd431fce9348a95261acac9e0c14779c35df8/verify-pipeline.mjs#L561-L597","documentation":"verify-pipeline.mjs check 15 audits which enabled portals.yml entries resolve to an ATS provider. When the coverage audit itself throws (bad config load, fetch failure, parse error), it is caught and downgraded to this warning instead of failing the whole health check.","triggerScenarios":"The try block wrapping the portal-coverage audit throws — e.g. portals.yml is unparseable, an entry lacks expected fields, or the provider-resolution helper rejects (network error fetching board data). The catch at verify-pipeline.mjs:569 emits warn(`Portal coverage check could not run: ${err.message}`).","commonSituations":" portals.yml edited by hand with a YAML typo; offline run of a check that fetches live board data; an enabled entry with a malformed careers_url; provider module change breaking resolution.","solutions":["Read err.message in the warning to identify the root cause (parse error vs fetch error)","Validate portals.yml parses: node -e \"import('js-yaml').then(y=>y.load(require('fs').readFileSync('portals.yml','utf8')))\" or run the project's config check","If it is a fetch failure, re-run when network is available — the check is deliberately non-fatal","Audit the entry flagged by audit-portals.mjs to confirm its provider/careers_url fields"],"exampleFix":"// before: portals.yml\n- name: Acme\n  careers_url: greenhouse/acme\n  enabled: true\n// after (fetch-failure case): just re-run online\nnode verify-pipeline.mjs\n// or disable the broken entry temporarily\n- name: Acme\n  careers_url: greenhouse/acme\n  enabled: false","handlingStrategy":"fallback","validationCode":"import { readFileSync } from 'fs';\nimport { load } from 'js-yaml';\nconst cfg = load(readFileSync('portals.yml', 'utf8'));\nconst bad = cfg.filter(e => e.enabled !== false && !e.careers_url);\nif (bad.length) console.warn('entries missing careers_url:', bad.map(e => e.name));","typeGuard":"const isEnabledEntry = (e) => Boolean(e && typeof e === 'object' && typeof e.careers_url === 'string' && e.enabled !== false);","tryCatchPattern":"try {\n  await runPortalCoverageCheck();\n} catch (err) {\n  console.warn(`Portal coverage check could not run: ${err.message}`); // non-fatal by design\n}","preventionTips":["Keep portals.yml valid YAML and validate after every hand edit","Run audit-portals.mjs after adding companies to confirm each entry resolves to a provider","Run verify-pipeline.mjs with network available so fetch-based checks can complete"],"tags":["health-check","config","portals","audit"],"backgroundTag":"http-request-failed","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"}