santifer/career-ops · error · Error

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

Error message

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

What it means

When parser.command is a whitelisted interpreter (no slash, in ALLOWED_INTERPRETERS), the invocation must run an in-repo parser script as its first argument. This blocks interpreter options like node --eval or python -c that would execute arbitrary inline code from a semi-trusted config. If no script path can be detected (parser.script absent and no arg matching *.py|mjs|js|sh), this error is thrown.

Solutions

  1. Set parser.script explicitly to the in-repo script path, e.g. parser: {command: python3, script: parsers/jobs.py, args: [...]}.
  2. Rename the script so it has a recognized extension (.py, .mjs, .js, .sh) so it can be auto-detected from args.
  3. Replace inline code (python -c, node -e) with a committed in-repo script file.
  4. Remember the script must also be the interpreter's first argument (see the companion first-argument error).

Example fix

// before (portals.yml)
parser: {command: node, args: ["--eval", "fetch('https://x').then(r=>r.text()).then(console.log)"]}
// after
parser: {command: node, script: parsers/fetch-jobs.mjs}
Defensive patterns

Strategy: validation

Validate before calling

const scriptExts = /\.(py|mjs|js|sh)$/;
const hasScript = Boolean(entry.parser?.script) || (entry.parser?.args || []).some(a => !String(a).startsWith('-') && scriptExts.test(String(a)));
if (!String(entry.parser?.command || '').includes('/') && hasScript === false) {
  throw new Error(`${entry.name}: interpreter command needs parser.script or a *.py/.mjs/.js/.sh arg`);
}

Try / catch

try {
  await localParser.fetch(entry);
} catch (e) {
  if (String(e.message).includes('interpreter command requires an in-repo parser script')) {
    console.error(`${entry.name}: no inline code — set parser.script to an in-repo file`);
    return [];
  }
  throw e;
}

Prevention

When it happens

Trigger: Entry like parser: {command: python3, args: ["-c", "import ..."]} or {command: node, args: ["--eval", "..."]} — scriptPath is null because parser.script is unset and no arg matches the script extension heuristic.

Common situations: Porting a shell one-liner into portals.yml; using python -c / node -e for quick scraping; a script whose extension isn't .py/.mjs/.js/.sh (e.g. .tsx or extensionless) so getParserScriptPath() misses it; forgetting the `script:` key when the script arg also carries placeholders.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/e82fe61b1ae6b6e3. Report an issue: GitHub.

Appendix: 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 aac998c7ed)