santifer/career-ops · error

changedSections must be an array

Error message

changedSections must be an array

What it means

Thrown by writeReuseDecision() when changedSections is not an Array. The field records which CV sections changed (serialized as changed_sections in the JSON record); a bare Array.isArray check guards it because strings are the common accidental shape.

Source

Thrown at application-artifacts.mjs:87

    join(paths.root, 'cv', 'source'),
    paths.cv.tailored.root,
    join(paths.root, 'decision'),
  ]) mkdirSync(directory, { recursive: true });
  return paths;
}

/** Write an auditable CV reuse decision beside the application artifacts. */
export function writeReuseDecision(paths, {
  decision,
  score = null,
  sourceCv = null,
  currentJd = null,
  previousSource = null,
  changedSections = [],
  userOverride = false,
}) {
  if (!DECISIONS.has(decision)) throw new Error(`decision must be one of: ${[...DECISIONS].join(', ')}`);
  if (!Array.isArray(changedSections)) throw new Error('changedSections must be an array');
  ensureApplicationArtifactDirs(paths);
  const record = {
    schema_version: 1,
    decision,
    score,
    source_cv: sourceCv,
    current_jd: currentJd,
    previous_source: previousSource,
    changed_sections: changedSections,
    user_override: Boolean(userOverride),
    recorded_at: new Date().toISOString(),
  };
  writeFileSync(paths.decision.reuse, `${JSON.stringify(record, null, 2)}\n`);
  return record;
}

function usage() {
  return 'Usage: node application-artifacts.mjs --report N --company NAME --role ROLE [--version N] [--root output] [--init]';

View on GitHub (pinned to 60398d6549)

Solutions

  1. Pass a real array: changedSections: ['summary', 'skills']
  2. If the value arrives as a string, split it first: typeof s === 'string' ? s.split(',').map(x => x.trim()).filter(Boolean) : s
  3. When nothing changed, omit the field entirely — the default [] is valid

Example fix

// before
writeReuseDecision(paths, { decision: 'reuse', changedSections: 'summary, skills' });

// after
writeReuseDecision(paths, { decision: 'reuse', changedSections: ['summary', 'skills'] });
Defensive patterns

Strategy: type-guard

Validate before calling

if (changedSections !== undefined && !Array.isArray(changedSections)) {
  throw new TypeError('changedSections must be an array of section names');
}

Type guard

function isSectionList(v) {
  return v === undefined || (Array.isArray(v) && v.every((s) => typeof s === 'string'));
}

Prevention

When it happens

Trigger: changedSections: 'summary, skills' (comma-separated string), changedSections: 'summary', or an object keyed by section name. The parameter defaults to [] so the throw always comes from an explicitly passed non-array.

Common situations: Passing a human-readable list as one string; a caller upstream joining an array with ', ' for logging and reusing the joined value; config-driven call sites reading the field from YAML/JSON that holds a string.

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@60398d6549 (2026-08-20). Data as JSON: /api/errors/598a07e5b0c7d82f. Report an issue: GitHub.