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

  1. Add a command to the entry's parser block, e.g. parser: {command: node, args: ["parsers/jobs.js"]}.
  2. Check the YAML key spelling — it must be exactly `command` under `parser`.
  3. Ensure template/placeholder substitution didn't blank the value (inspect the rendered portals.yml).
  4. 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

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


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)