santifer/career-ops · error · Error
local-parser: parser.command is required
Error message
local-parser: parser.command is required
What it means
resolveCommand() requires a non-empty parser.command. The command must be either a whitelisted interpreter name (python3, python, node, deno, bun, sh, bash, without slashes) or an in-repo file path; an empty/missing command fails immediately with this error.
Solutions
- Add a command to the entry's parser block, e.g. parser: {command: node, args: ["parsers/jobs.js"]}.
- Check the YAML key spelling — it must be exactly `command` under `parser`.
- Ensure template/placeholder substitution didn't blank the value (inspect the rendered portals.yml).
- Note detect() already returns null when parser.command is missing — make sure entry selection relies on detect() before fetch().
Example fix
// before (portals.yml)
parser: {args: ["parsers/jobs.js"]}
// after
parser: {command: node, args: ["parsers/jobs.js"]} Defensive patterns
Strategy: validation
Validate before calling
if (!entry.parser || !String(entry.parser.command || '').trim()) {
throw new Error(`${entry.name}: parser.command is required (python3|node|... or an in-repo script path)`);
} Type guard
function hasParserCommand(entry) {
return typeof entry.parser === 'object' && entry.parser !== null && typeof entry.parser.command === 'string' && entry.parser.command.trim().length > 0;
} Try / catch
try {
await localParser.fetch(entry);
} catch (e) {
if (String(e.message).includes('parser.command is required')) {
console.error(`${entry.name}: add parser: {command: node, args: [...]} to portals.yml`);
return [];
}
throw e;
} Prevention
- Only select entries whose provider detect() returned non-null — it already rejects missing command.
- Keep a parser block template with command filled in; never leave command blank after substitution.
- Validate YAML keys (command, not cmd) when hand-editing portals.yml.
- Add a config smoke test that resolves every parser invocation at startup.
When it happens
Trigger: Calling runLocalParser/resolveInvocation on an entry where entry.parser exists but parser.command is undefined, null, empty string, or whitespace-only (String(command || '') collapses falsy values to '').
Common situations: YAML parser block written with only `args:` and no `command:`; command key misspelled (e.g. `cmd:`); command accidentally set to '' or ~ (null) after template substitution; detect() returning null and a caller invoking fetch() anyway through a different path.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- apify: entry missing 'actor' (e.g. misceres/indeed-scraper)
- jibeapply: careers_url required
- apify: entry has invalid field_map. Each of title, url…
- arbeitnow: invalid URL
- arbeitsagentur: entry
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/80915fd52f7d2ce7.
Report an issue: GitHub.
Appendix: source
Thrown at providers/local-parser.mjs:94
if (Array.isArray(parser.args)) args.push(...parser.args);
return args.map(arg => expandParserArg(arg, entry));
}
// Resolve a configured path and confirm it stays inside the project tree.
function resolveInsideRoot(rawPath) {
const resolved = realpathSync(resolve(PROJECT_ROOT, String(rawPath)));
if (resolved !== PROJECT_ROOT && !resolved.startsWith(PROJECT_ROOT + sep)) {
throw new Error(`local-parser: path escapes the project root: ${rawPath}`);
}
return resolved;
}
// The command is either a whitelisted interpreter (resolved via PATH) or a script
// that lives inside the repo. Anything else is rejected.
function resolveCommand(command) {
const value = String(command || '');
if (!value) throw new Error('local-parser: parser.command is required');
if (!value.includes('/') && ALLOWED_INTERPRETERS.has(value)) return value;
return resolveInsideRoot(value);
}
// Validate the whole invocation and return what to spawn. Throws on anything unsafe.
function resolveInvocation(entry) {
const rawCommand = String(entry.parser?.command || '');
const command = resolveCommand(rawCommand);
const args = buildParserArgs(entry);
const scriptPath = getParserScriptPath(entry);
const usesInterpreter = !rawCommand.includes('/') && ALLOWED_INTERPRETERS.has(rawCommand);
if (usesInterpreter) {
// A whitelisted interpreter must run an in-repo script as its FIRST argument.
// Anything before the script is an interpreter option (node --eval / --require,
// python -c, …) that could execute arbitrary code, so require the script to lead.
if (!scriptPath) throw new Error('local-parser: interpreter command requires an in-repo parser script');
resolveInsideRoot(scriptPath);View on GitHub (pinned to aac998c7ed)