santifer/career-ops · error · Error

version must be a positive integer

Error message

version must be a positive integer

What it means

Validation in `applicationArtifactPaths`: the optional `version` (default 1) coerced to string must match `/^\d+$/` AND its numeric value must be ≥ 1. Rejects zero, negatives, decimals, and non-numeric strings, because versions index the `cv/tailored/vNNN` subdirectory and an invalid version would create an unusable path.

Source

Thrown at application-artifacts.mjs:35

const DECISIONS = new Set(['reuse', 'reuse-with-edits', 'regenerate']);

/** Convert a user-facing label into a safe, readable path segment. */
export function slugifySegment(value, fallback = 'application') {
  const slug = String(value ?? '')
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
  return slug || fallback;
}

/** Return all stable paths belonging to one application artifact bundle. */
export function applicationArtifactPaths({ reportNum, company, role, version = 1, root = DEFAULT_OUTPUT_ROOT }) {
  if (!/^\d+$/.test(String(reportNum ?? ''))) {
    throw new Error('reportNum must be a numeric report number');
  }
  if (!/^\d+$/.test(String(version ?? '')) || Number(version) < 1) {
    throw new Error('version must be a positive integer');
  }
  const key = `${String(reportNum).padStart(3, '0')}-${slugifySegment(company)}-${slugifySegment(role, 'role')}`;
  const applicationRoot = join(resolve(root), key);
  const tailoredRoot = join(applicationRoot, 'cv', 'tailored', `v${String(version).padStart(3, '0')}`);
  return {
    key,
    root: applicationRoot,
    jd: {
      current: join(applicationRoot, 'jd', 'current.md'),
      previous: join(applicationRoot, 'jd', 'previous.md'),
    },
    cv: {
      source: {
        html: join(applicationRoot, 'cv', 'source', 'original.html'),
        pdf: join(applicationRoot, 'cv', 'source', 'original.pdf'),
      },
      tailored: {
        root: tailoredRoot,

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Pass a positive integer: omit it (defaults to 1) or supply `version: 2`, `3`, etc.
  2. Compute the next version explicitly upstream: `const next = (maxExisting || 0) + 1;` then pass `version: next`.
  3. Strip non-digits and validate before calling.
  4. Never use zero or negative versions — the directory layout is `v001`, `v002`, … so version 1 is the first.
  5. Add a test for the 0, negative, and non-numeric rejection paths.

Example fix

// before
applicationArtifactPaths({ reportNum: 42, company: 'acme', role: 'swe', version: 0 }); // throws
// after
applicationArtifactPaths({ reportNum: 42, company: 'acme', role: 'swe', version: 1 });
Defensive patterns

Strategy: validation

Validate before calling

function positiveIntVersion(v) {
  const n = Number(v ?? 1);
  if (!Number.isInteger(n) || n < 1) throw new Error(`version must be a positive integer, got: ${v}`);
  return n;
}

Type guard

function isPositiveIntVersion(v) {
  const n = Number(v);
  return Number.isInteger(n) && n >= 1;
}

Prevention

When it happens

Trigger: Passing `version: 0`, `version: -1`, `version: 1.5`, `version: 'v2'`, `version: ''`, `version: 'latest'`, or `version: undefined`-as-string. Each fails either the digit-only regex or the `< 1` numeric check.

Common situations: Caller defaults new versions to 0 expecting auto-increment (the function does not auto-increment); passes a 'v2'-style label; reads version from a config that allowed null; arithmetic producing 0/NaN; off-by-one in a versioning loop.

Related errors


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