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. If entry.parser.command is missing, empty, or coerces to an empty string, this error fires before any path resolution or interpreter lookup happens.

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 9b17a8ac97)

Solutions

  1. Add parser.command to the entry (a whitelisted interpreter like 'python3' or an in-repo script path).
  2. Check YAML indentation — parser.command must be nested under parser:.
  3. Confirm the key is spelled exactly 'command'.

Example fix

# before
- name: Acme
  provider: local-parser
  parser: { script: parsers/acme.py, args: ['{careers_url}'] }

# after
- name: Acme
  provider: local-parser
  parser: { command: python3, script: parsers/acme.py, args: ['{careers_url}'] }
Defensive patterns

Strategy: validation

Validate before calling

export function hasParserCommand(entry) {
  return typeof entry?.parser?.command === 'string' && entry.parser.command.trim().length > 0;
}
// if (!hasParserCommand(entry)) failConfig(`local-parser entry ${entry.name} missing parser.command`);

Type guard

/** @param {any} entry */
function hasCommand(entry) {
  return Boolean(entry?.parser?.command && String(entry.parser.command).trim());
}

Try / catch

try {
  await provider.fetch(entry, ctx);
} catch (err) {
  if (err.message === 'local-parser: parser.command is required') console.warn(`add parser.command to ${entry.name}`);
  throw err;
}

Prevention

When it happens

Trigger: entry.parser is unset, or entry.parser.command is '', null, or undefined. resolveInvocation calls resolveCommand(String(entry.parser?.command || '')), so any falsy value reaches the empty check.

Common situations: A local-parser entry was added without a parser block; the parser.command key was misspelled (e.g. cmd); YAML indentation put command under the wrong nesting; the value was left blank.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/80915fd52f7d2ce7. Report an issue: GitHub.