santifer/career-ops · error · Error
local-parser: the parser script must be the interpreter's…
Error message
local-parser: the parser script must be the interpreter's first argument
What it means
For a whitelisted interpreter command, the in-repo parser script must be args[0]. Anything before the script could be an interpreter option (node --require, python -c) that executes arbitrary code, so resolveInvocation() enforces the script leads the argument list.
Solutions
- Reorder parser.args so the script path is the first element; pass interpreter flags via the command's supported config or drop them.
- If parser.script is set and args also includes the script, remove the duplicate and keep args[0] equal to the script path string.
- Verify after {careers_url}/{company} expansion that args[0] still string-equals the script path (expansion can change the string).
- Use the direct in-repo-file form instead (command: parsers/jobs.py style) if you don't need interpreter options — no shebang/exec bit needed only for interpreters, so prefer keeping the interpreter with the script first.
Example fix
// before (portals.yml)
parser: {command: python3, script: parsers/jobs.py, args: ["-u", "parsers/jobs.py"]}
// after
parser: {command: python3, script: parsers/jobs.py, args: ["parsers/jobs.py", "-u"]} Defensive patterns
Strategy: validation
Validate before calling
const scriptPath = String(entry.parser?.script || (entry.parser?.args || []).find(a => /\.(py|mjs|js|sh)$/.test(String(a))) || '');
const first = String((entry.parser?.args || [])[0] || '');
if (scriptPath && first !== scriptPath) throw new Error(`${entry.name}: script must be parser.args[0]`); Try / catch
try {
await localParser.fetch(entry);
} catch (e) {
if (String(e.message).includes("must be the interpreter's first argument")) {
console.error(`${entry.name}: reorder parser.args so the script path comes first`);
return [];
}
throw e;
} Prevention
- Put the script path as the first element of parser.args whenever parser.script is set.
- Avoid duplicating the script in both script: and args:.
- Re-verify arg order after placeholder expansion.
- Skip interpreter flags (-u, etc.) unless the script still leads args.
When it happens
Trigger: Entry where a script is detected (via parser.script or a *.py/.mjs/.js/.sh arg) but the expanded args array does not start with it — e.g. {command: python3, script: parsers/jobs.py, args: ["-u", "parsers/jobs.py"]} puts '-u' first.
Common situations: Adding interpreter flags (-u, --harmony, -O) before the script path; parser.script set while parser.args also repeats the script after some flag; placeholder expansion reordering assumptions; copying a shell invocation verbatim into args.
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
- breezy: untrusted hostname
- breezy: URL must use HTTPS
- builtin: untrusted hostname
- builtin: URL must use HTTPS
- careerviet: untrusted hostname
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/b1e5e743d5b35389.
Report an issue: GitHub.
Appendix: source
Thrown at providers/local-parser.mjs:114
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)