santifer/career-ops · error · Error

local-parser: interpreter command requires an in-repo parser

Error message

local-parser: interpreter command requires an in-repo parser script

What it means

When parser.command is a whitelisted interpreter (python3/python/node/deno/bun/sh/bash — no '/' and in ALLOWED_INTERPRETERS), the provider requires a corresponding in-repo parser script path. If getParserScriptPath returns nothing (no parser.script / detectable script arg), this error fires. The rule prevents running an interpreter with no controlled script, which could otherwise let interpreter options execute arbitrary code.

Source

Thrown at providers/local-parser.mjs:111

  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);
    if (args[0] !== scriptPath) {
      throw new Error('local-parser: the parser script must be the interpreter\'s first argument');
    }
  } else if (scriptPath) {
    // command is an in-repo file; keep any detected script path inside the repo too.
    resolveInsideRoot(scriptPath);
  }

  return { command, args };
}

function normalizeJobUrl(rawUrl, baseUrl) {
  if (!rawUrl) return '';
  try {
    return new URL(String(rawUrl).trim(), baseUrl || undefined).href;
  } catch {
    return '';

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Add parser.script pointing at an in-repo script, e.g. script: parsers/acme.py.
  2. Ensure the script path is under the project root (it will be checked by resolveInsideRoot next).
  3. If you intended a self-contained command without a script, local-parser is the wrong provider — write a script file.

Example fix

# before
parser: { command: python3, args: ['{careers_url}'] }

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

Strategy: validation

Validate before calling

const INTERPRETERS = new Set(['python3','python','node','deno','bun','sh','bash']);
export function interpreterHasScript(entry) {
  const cmd = String(entry?.parser?.command || '');
  if (!cmd || cmd.includes('/') || !INTERPRETERS.has(cmd)) return true; // not an interpreter command
  return Boolean(entry?.parser?.script);
}

Type guard

const INTERPRETERS = new Set(['python3','python','node','deno','bun','sh','bash']);
/** @param {any} entry */
function isValidInterpreterEntry(entry) {
  const cmd = String(entry?.parser?.command || '');
  if (!INTERPRETERS.has(cmd)) return true;
  return typeof entry?.parser?.script === 'string' && entry.parser.script.length > 0;
}

Try / catch

try {
  await provider.fetch(entry, ctx);
} catch (err) {
  if (err.message.includes('requires an in-repo parser script')) console.warn(`add parser.script to ${entry.name}`);
  throw err;
}

Prevention

When it happens

Trigger: entry.parser.command is 'python3' (or another whitelisted interpreter) but parser.script is unset and no arg looks like a script path. usesInterpreter is true, scriptPath is falsy.

Common situations: An entry sets command: node but forgets script:; the script path was put in a different key; the parser args were intended to be inline code (not allowed — see error 254).

Related errors


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