santifer/career-ops · error · Error

Invalid YAML in profile file: ${customProfilePath}

Error message

Invalid YAML in profile file: ${customProfilePath}

What it means

Inside loadProfile, after reading the explicitly provided profile file, the parsed YAML must yield a non-null object; null, a scalar, or an array-equivalent fails this check and throws. Note this thrown Error is immediately caught by the surrounding catch and rethrown as error 305, so in practice callers see the wrapper message containing this text plus the original reason.

Source

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

}

/**
 * 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}`);
    }
  }

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Open the file and add valid top-level YAML mapping content (name:, email:, etc.) — an empty or comment-only file parses to null.
  2. Validate before calling: `const d = yaml.load(readFileSync(p,'utf8')); if (!d || typeof d !== 'object') throw ...` to get a clearer standalone error.
  3. Confirm you passed the intended profile file, not an empty template or unrelated YAML.

Example fix

// before (empty profile.yml)
# TODO: fill in

// after
name: Ada Lovelace
email: ada@example.com
location: Taipei
Defensive patterns

Strategy: type-guard

Validate before calling

import { readFileSync } from 'node:fs';
import yaml from 'js-yaml';
const doc = yaml.load(readFileSync(customProfilePath, 'utf8'));
if (doc === null || typeof doc !== 'object') {
  throw new Error(`${customProfilePath} is empty or not a YAML mapping — fill it in`);
}

Type guard

function isYamlMapping(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v) && Object.keys(v).length > 0;
}

Try / catch

try {
  const profile = loadProfile(customProfilePath);
} catch (e) {
  if (e.message.includes('Failed to read profile file') && e.message.includes('Invalid YAML')) {
    console.error('Profile parsed to null/primitive — file is empty or comment-only. Fill in profile values.');
  } else throw e;
}

Prevention

When it happens

Trigger: yaml.load on the custom profile returns null/undefined/primitive: an empty file, a file containing only comments, a document that is just a scalar (e.g. 'name only'), or invalid YAML that js-yaml happens to parse into null (e.g. '---' alone).

Common situations: Saving an empty profile.yml placeholder; a merge conflict marker file; editor wrote only comments; truncation during copy; using a .yml template never filled in; wrong file passed (e.g. a lockfile or TSV).

Related errors


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