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
- Set parser.script explicitly to the in-repo script path, e.g. parser: {command: python3, script: parsers/jobs.py, args: [...]}.
- Rename the script so it has a recognized extension (.py, .mjs, .js, .sh) so it can be auto-detected from args.
- Replace inline code (python -c, node -e) with a committed in-repo script file.
- 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
- Always set parser.script explicitly instead of relying on extension auto-detection.
- Never put inline code (python -c, node -e) in portals.yml.
- Name parser files with recognized extensions (.py, .mjs, .js, .sh).
- Run detect() over all entries in CI to catch unresolvable invocations early.
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
- a 40-hex commit --sha is required
- apify: entry has invalid field_map. Each of title, url…
- apify: entry missing 'actor' (e.g. misceres/indeed-scraper)
- arbeitnow: invalid URL
- arbeitnow: URL must use HTTPS
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)