santifer/career-ops · error · Error

Failed to read profile file at ${customProfilePath}: ${err.m

Error message

Failed to read profile file at ${customProfilePath}: ${err.message}

What it means

The try/catch around reading and parsing the explicitly supplied profile file converts any failure — fs read errors (ENOENT, EACCES, EISDIR) and the nested Invalid-YAML error 304 — into this single wrapped error. The original cause is preserved in err.message appended after the path. It exists so callers get one consistent message for 'your custom profile could not be loaded'.

Source

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

 * Loads profile and CV data from file paths or default paths.
 * Fails closed if real profile configuration is missing.
 */
export function loadProfile(customProfilePath = null, customCvPath = null) {
  let profileRaw = null;
  const profileSource = customProfilePath || process.env.CAREER_OPS_PROFILE || 'config/profile.yml';

  if (customProfilePath) {
    if (!existsSync(customProfilePath)) {
      throw new Error(`Profile configuration file not found at: ${customProfilePath}`);
    }
    try {
      const content = readFileSync(customProfilePath, 'utf8');
      profileRaw = yaml.load(content);
      if (!profileRaw || typeof profileRaw !== 'object') {
        throw new Error(`Invalid YAML in profile file: ${customProfilePath}`);
      }
    } catch (err) {
      throw new Error(`Failed to read profile file at ${customProfilePath}: ${err.message}`);
    }
  } else {
    if (!existsSync(profileSource)) {
      throw new Error('config/profile.yml not found: fill it in first');
    }
    try {
      const content = readFileSync(profileSource, 'utf8');
      profileRaw = yaml.load(content);
      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';

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Read the `: ${err.message}` suffix — it names the real cause (ENOENT/EACCES/YAML syntax) and fix that underlying problem.
  2. Fix YAML syntax: replace tabs with spaces, close quotes/brackets, ensure `key: value` form; test with `node -e "console.log(require('js-yaml').load(require('fs').readFileSync(p,'utf8')))"`.
  3. Check file permissions and that the path is a regular readable file (fs.statSync(p).isFile()).

Example fix

// before (tab-indented YAML -> parse error)
name:\tAda

// after
name: Ada
Defensive patterns

Strategy: try-catch

Validate before calling

import { statSync, readFileSync } from 'node:fs';
import yaml from 'js-yaml';
statSync(customProfilePath); // throws early with the true fs error
const raw = yaml.load(readFileSync(customProfilePath, 'utf8')); // surfaces true YAML syntax errors unwrapped

Try / catch

try {
  const profile = loadProfile(customProfilePath);
} catch (e) {
  if (e.message.startsWith('Failed to read profile file at')) {
    const cause = e.message.split(': ').slice(1).join(': '); // original err.message
    console.error(`Profile load failed — underlying cause: ${cause}`);
    // route EACCES->permissions fix, YAML messages->syntax fix, ENOENT->path fix
  } else throw e;
}

Prevention

When it happens

Trigger: readFileSync(customProfilePath) throws (permission denied, path is a directory, file vanished between existsSync and read) OR yaml.load throws a syntax error OR the nested `Invalid YAML` error is raised — all funnel into this rethrow.

Common situations: Profile file unreadable due to file permissions (chmod 000); passing a directory instead of a file; YAML syntax mistakes (tabs for indentation, unbalanced quotes); the file being a symlink to a missing target; race where another process deletes the file.

Related errors


AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/d4914ce49c1bc586. Report an issue: GitHub.