santifer/career-ops · warning
portals.yml: an enabled entry has no name
Error message
portals.yml: an enabled entry has no name (careers_url: ${e.careers_url || 'none'}) — it cannot be provider-checked; give it a name What it means
verify-pipeline.mjs Check 15 warns about malformed portals.yml entries: an entry is enabled (enabled !== false) but has no usable `name` string. Such an entry can't be claimed by any provider, so it is excluded from provider checking and from the 'All N entries resolve' success count — it would silently never scan.
Solutions
- Open portals.yml and give the listed entry a non-empty `name:` string
- Ensure `name` is a plain scalar, not null or a nested block
- Re-run verify-pipeline.mjs; the entry should then receive a provider check
- Optionally run `node audit-portals.mjs` afterwards to confirm the board actually answers
Example fix
# before - careers_url: https://boards.greenhouse.io/acme enabled: true # after - name: Acme careers_url: https://boards.greenhouse.io/acme enabled: true
Defensive patterns
Strategy: validation
Validate before calling
const malformed = entries.filter(e => e && e.enabled !== false && (typeof e.name !== 'string' || !e.name.trim()));
if (malformed.length) throw new Error('portals.yml entries missing name: ' + malformed.map(e => e.careers_url).join(', ')); Type guard
const hasName = (e) => e && typeof e.name === 'string' && e.name.trim().length > 0;
Prevention
- Validate portals.yml after every edit (verify-pipeline.mjs check 15)
- Never write `name:` without a value
- Copy an existing entry as a template when adding companies
- Keep one entry per YAML list item — avoid merge artifacts
When it happens
Trigger: Running `node verify-pipeline.mjs` after hand-editing portals.yml and adding an entry with a missing name, a name of ""/whitespace, or a name that isn't a string (e.g. a number or a nested map).
Common situations: YAML mistake like writing `name:` with no value; duplicating an entry and deleting the name line; a merge conflict resolved leaving the name out.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Invalid YAML in profile file
- Malformed states file at
- apify: entry has invalid field_map. Each of title, url…
- apify: entry missing 'actor' (e.g. misceres/indeed-scraper)
- arbeitnow: invalid URL
AI-assisted analysis of santifer/career-ops@e7abd431fc (2026-09-16).
Data as JSON: /api/errors/6df69f7595848765.
Report an issue: GitHub.
Appendix: source
Thrown at verify-pipeline.mjs:563
// CODE_ROOT (scan.mjs does the same). Without mergeProviderPlugins() the
// health check sees only providers/*.mjs and reports every enabled
// plugin-provider entry as an unknown provider that "never scans", while
// the scanner resolves and scans it (#4026). No-op for a plugin-free
// install: mergeProviderPlugins returns before any work when
// config/plugins.yml is absent.
const providers = await loadProviders(join(CODE_ROOT, 'providers'));
await mergeProviderPlugins(providers, { root: CODE_ROOT });
const { silent, handoff, unknownProvider } = findUnclaimedEntries(entries, providers);
// findUnclaimedEntries silently skips an entry with no (or blank) `name` —
// it can't report what it can't label. Without this, that entry vanishes
// from silent/handoff/unknownProvider entirely, and the enabled count
// below (which doesn't share the same eligibility rule) would still
// include it — so a malformed entry never gets a provider check AND the
// "All N entries resolve" success line claims it as resolved anyway.
const malformed = entries.filter(e => e && e.enabled !== false && (typeof e.name !== 'string' || !e.name.trim()));
for (const e of malformed) {
warn(`portals.yml: an enabled entry has no name (careers_url: ${e.careers_url || 'none'}) — it cannot be provider-checked; give it a name`);
}
for (const e of unknownProvider) {
error(`portals.yml: "${e.name}" sets an unknown provider — ${e.error}. The entry never scans (see providers/ for valid ids)`);
}
for (const e of silent) {
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)`);
}
if (silent.length === 0 && unknownProvider.length === 0 && malformed.length === 0) {
const enabled = entries.filter(e => e && e.enabled !== false).length;
ok(handoff.length > 0
? `All ${enabled - handoff.length} scannable portals.yml entries resolve to a provider (${handoff.length} on websearch handoff)`
: `All ${enabled} enabled portals.yml entries resolve to a provider`);
}
} catch (err) {
warn(`Portal coverage check could not run: ${err.message}`);
}
}View on GitHub (pinned to e7abd431fc)