santifer/career-ops · error · Error

Failed to read CV file at

Error message

Failed to read CV file at ${customCvPath}: ${err.message}

What it means

Thrown by loadProfile() when an explicit customCvPath exists but reading or parsing it fails — readFileSync error or an exception from parseCvMarkdown(). The raw cause is wrapped into a single message naming the path.

Solutions

  1. Read the wrapped err.message for the root cause (EACCES, EISDIR, or the parseCvMarkdown error text).
  2. Confirm the file is plain-text UTF-8 markdown with the standard sections (Summary, Experience, Education, Skills).
  3. Check permissions and that the path is a regular file (not a directory or symlink to nothing).
  4. Restore cv.md structure per the project's convention (standard markdown headings) or re-export the CV.

Example fix

# before: cv.md is a binary PDF renamed to .md
$ file cv.md  # PDF document
# after: keep the real markdown at cv.md, or convert first
# pandoc cv.pdf -o cv.md
Defensive patterns

Strategy: try-catch

Validate before calling

import { statSync, readFileSync } from 'node:fs';
if (!statSync(cvPath).isFile()) throw new Error(`${cvPath} is not a regular file`);
readFileSync(cvPath, 'utf8'); // fails fast on permission/encoding problems

Try / catch

try {
  const profile = loadProfile(null, cvPath);
} catch (err) {
  if (err.message.includes(`Failed to read CV file at ${cvPath}`)) {
    console.error(`CV unreadable: ${err.message}`);
    const profile = loadProfile(null); // degrade gracefully without CV data
  } else throw err;
}

Prevention

When it happens

Trigger: loadProfile(profilePath, customCvPath) where the file exists but is unreadable (permissions, directory) or parseCvMarkdown throws on malformed/unexpected markdown structure.

Common situations: CV file with permissions too restrictive; path is actually a directory; CV markdown restructured so a section the parser expects (headings, bullet format) is missing or malformed; binary file (e.g. a PDF) saved as .md.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at scripts/export-ats-text.mjs:257

      if (!profileRaw || typeof profileRaw !== 'object') {
        throw new Error('config/profile.yml is empty or invalid YAML: fill it in first');
      }
    } catch (err) {
      throw new Error(`Failed to read profile file at ${profileSource}: ${err.message}`);
    }
  }

  let cvData = {};
  const cvSource = customCvPath || process.env.CAREER_OPS_CV || 'cv.md';
  if (customCvPath) {
    if (!existsSync(customCvPath)) {
      throw new Error(`CV file not found at: ${customCvPath}`);
    }
    try {
      const cvText = readFileSync(customCvPath, 'utf8');
      cvData = parseCvMarkdown(cvText);
    } catch (err) {
      throw new Error(`Failed to read CV file at ${customCvPath}: ${err.message}`);
    }
  } else if (existsSync(cvSource)) {
    try {
      const cvText = readFileSync(cvSource, 'utf8');
      cvData = parseCvMarkdown(cvText);
    } catch {
      // cv.md is optional if profile supplies necessary fields
    }
  }

  return normalizeProfile(profileRaw, cvData);
}

/**
 * Formats profile object into structured plain-text section blocks.
 */
export function formatAtsText(profile = {}, options = {}) {
  const normalized = normalizeProfile(profile);

View on GitHub (pinned to aac998c7ed)