santifer/career-ops · error · Error

config/profile.yml not found: fill it in first

Error message

config/profile.yml not found: fill it in first

What it means

When no customProfilePath argument is given, loadProfile falls back to CAREER_OPS_PROFILE or config/profile.yml and requires that default file to exist. This is the deliberate 'fails closed' onboarding gate: the exporter refuses to run on an uninitialized checkout instead of producing an empty ATS export. The message tells the user exactly which file to create.

Source

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

  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';
  if (customCvPath) {
    if (!existsSync(customCvPath)) {
      throw new Error(`CV file not found at: ${customCvPath}`);
    }

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Create and fill in config/profile.yml (name, email, phone, location, links) at the repository root — this is the intended fix per the onboarding steps.
  2. If your profile lives elsewhere, either export CAREER_OPS_PROFILE=/abs/path/profile.yml or pass it as the first argument to loadProfile.
  3. Run the exporter from the repository root (or fix the cwd) so the relative default path resolves.

Example fix

// before
$ node scripts/export-ats-text.mjs   # config/profile.yml missing

// after
$ export CAREER_OPS_PROFILE=$HOME/.career-ops/profile.yml
$ node scripts/export-ats-text.mjs
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs';
const source = process.env.CAREER_OPS_PROFILE || 'config/profile.yml';
if (!existsSync(source)) {
  throw new Error(`Run first-run onboarding: create ${source} (see config/profile.example.yml)`);
}
loadProfile();

Try / catch

try {
  const profile = loadProfile();
} catch (e) {
  if (e.message.includes('config/profile.yml not found')) {
    console.error('Setup incomplete: copy config/profile.example.yml to config/profile.yml and fill it in.');
    process.exitCode = 1;
  } else throw e;
}

Prevention

When it happens

Trigger: Calling loadProfile() (or loadProfile(null, cvPath)) in a repo where config/profile.yml does not exist and CAREER_OPS_PROFILE is unset — e.g. a fresh clone before onboarding, or running from a cwd where the relative path doesn't resolve.

Common situations: Fresh clone of career-ops before the first-run setup; running the script from a subdirectory so 'config/profile.yml' resolves wrong; CAREER_OPS_PROFILE set to a path that doesn't exist (env override also checked via existsSync and hits this same message); CI checkout without the gitignored personal config.

Related errors


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