santifer/career-ops · error · Error
Failed to read CV file at ${customCvPath}: ${err.message}
Error message
Failed to read CV file at ${customCvPath}: ${err.message} What it means
loadProfile in scripts/export-ats-text.mjs reads the user's CV markdown and parses it. When an explicit custom CV path was provided and readFileSync/parseCvMarkdown throws (missing permissions, unreadable file, or parse failure), the script wraps the underlying error in 'Failed to read CV file at <path>' so the developer knows which CV file could not be processed. Note that a missing file is handled earlier with a distinct 'CV file not found' error, so this error means the file exists but reading or parsing it failed.
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 1696bec4d0)
Solutions
- Check that the custom CV path points to a regular readable file (not a directory) and that the current user has read permission; fix with chmod/chown if needed
- Convert the CV to UTF-8 plain-text markdown (e.g. `file -bi cv.md` to verify encoding; re-export from PDF/DOCX to .md)
- Run the read manually (`cat <path>`) to see the underlying err.message included in the error and address it directly
- If the default CV should be used instead, drop the custom path so the script falls back to the default cvSource branch
Example fix
// before node scripts/export-ats-text.mjs --cv ./cv.pdf // Error: Failed to read CV file at ./cv.pdf: ... // after: export the CV as UTF-8 markdown first pandoc cv.pdf -o cv.md node scripts/export-ats-text.mjs --cv ./cv.md
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, statSync, accessSync, constants } from 'fs';
function cvFileIsReadable(p) {
if (!p || !existsSync(p)) return false;
if (!statSync(p).isFile()) return false;
try { accessSync(p, constants.R_OK); return true; } catch { return false; }
}
// call before: if (!cvFileIsReadable(customCvPath)) { /* fix path/perms or fall back to default cvSource */ } Try / catch
try {
cvData = parseCvMarkdown(readFileSync(customCvPath, 'utf8'));
} catch (err) {
console.error(`CV unreadable/unparseable (${customCvPath}): ${err.message}; falling back to default cv.md`);
cvData = parseCvMarkdown(readFileSync(DEFAULT_CV, 'utf8'));
} Prevention
- Verify the custom CV is a regular, readable UTF-8 file before passing it (file -bi, ls -l)
- Keep CVs in plain-text markdown, never PDF/DOCX renamed to .md
- Run export scripts from an account with read access to all input files
- When the file fails, fall back to the default cv.md rather than aborting
When it happens
Trigger: Calling loadProfile (or the script CLI) with --cv/customCvPath pointing to an existing file that: cannot be read by the current OS user (permission denied), is a directory, is binary/invalid UTF-8 (readFileSync throws ERR_INVALID_ARG_VALUE or similar), or whose content makes parseCvMarkdown throw.
Common situations: Passing a path with a typo that happens to point to a directory; running the script as a user without read permission on the CV (e.g. chmod 600 owned by another user); feeding a PDF or DOCX renamed to .md; a CV with markup that trips the markdown parser.
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
- ⚠️ Could not save report: ${err.message}
- cannot read ${rel || '.'}: ${err.message}
- refusing to hash symlink: ${childRel}
- refusing to hash non-regular file: ${childRel}
- Profile configuration file not found at: ${customProfilePath
AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01).
Data as JSON: /api/errors/3a4b2d5771c2e2e3.
Report an issue: GitHub.