santifer/career-ops · error · Error

local-parser: company name cannot start with

Error message

local-parser: company name cannot start with '-': ${value}

What it means

safeCompany() validates the {company} placeholder before argv interpolation. Because execFile passes args verbatim (no shell), the only injection risk is a value that looks like a CLI flag; a company name starting with '-' would be read as an option by the parser process, so it is rejected.

Solutions

  1. Rename the entry in portals.yml so name does not begin with '-', or strip the leading character.
  2. Quote the YAML value properly so a leading dash is part of the intended name only if you also change it (this validator will still reject it — reword instead).
  3. Move the flag-like token out of the company name, e.g. 'Acme-404' instead of '-404 Acme'.
  4. If the parser genuinely needs a flag-like value, pass it via a dedicated non-interpolated parser arg, not via {company}.

Example fix

// before (portals.yml)
- name: "-404 Studio"
  parser: {command: node, args: ["parsers/jobs.js", "{company}"]}
// after
- name: "Studio 404"
  parser: {command: node, args: ["parsers/jobs.js", "{company}"]}
Defensive patterns

Strategy: validation

Validate before calling

const name = String(entry.name || '').trim();
if (name.startsWith('-')) throw new Error(`${entry.name}: company name must not start with '-' (would be read as a CLI flag)`);

Try / catch

try {
  await localParser.fetch(entry);
} catch (e) {
  if (String(e.message).includes("cannot start with '-'")) {
    console.error(`Rename ${entry.name}: leading '-' looks like a CLI flag to the parser process`);
    return [];
  }
  throw e;
}

Prevention

When it happens

Trigger: A portals.yml entry whose parser args contain `{company}` and whose entry.name (after trim) starts with '-', e.g. name: ' - Acme' or a name like '-404 Studio'.

Common situations: Leading dash/hyphen from copy-paste artifacts (bullets, dashes); negative-number-like slugs used as company identifiers; YAML values that accidentally begin with '-' due to quoting mistakes.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at providers/local-parser.mjs:43

  let url;
  try {
    url = new URL(String(value));
  } catch {
    throw new Error(`local-parser: careers_url is not a valid URL: ${value}`);
  }
  if (url.protocol !== 'http:' && url.protocol !== 'https:') {
    throw new Error(`local-parser: careers_url must be http(s): ${value}`);
  }
  return url.href;
}

function safeCompany(value) {
  if (!value) return '';
  const name = String(value).trim();
  // execFile passes args verbatim (no shell), so the only injection risk is a
  // value that begins like a CLI flag.
  if (name.startsWith('-')) {
    throw new Error(`local-parser: company name cannot start with '-': ${value}`);
  }
  return name;
}

// Only validate a placeholder's value when the arg actually uses it — a fixed
// `parser.script` must not be rejected because some unrelated `{company}` value
// has punctuation it never sees.
function expandParserArg(value, entry) {
  let out = String(value);
  if (out.includes('{careers_url}')) out = out.replaceAll('{careers_url}', safeCareersUrl(entry.careers_url));
  if (out.includes('{company}')) out = out.replaceAll('{company}', safeCompany(entry.name));
  return out;
}

function getParserScriptPath(entry) {
  const parser = entry.parser || {};
  if (parser.script) return expandParserArg(parser.script, entry);

View on GitHub (pinned to aac998c7ed)