santifer/career-ops · warning

⚠️ Could not parse config/profile.yml

Error message

⚠️   Could not parse config/profile.yml: ${err.message}

What it means

gemini-eval.mjs wraps its config/profile.yml load (yaml.load) in a try/catch; when parsing or reading the file throws — invalid YAML syntax, wrong top-level types, or an unreadable file — this warning reports err.message and the language/modes_dir resolution is skipped entirely, leaving PATHS.shared and PATHS.oferta pointed at the default modes/. The evaluation continues with defaults; the profile's language settings are ignored for this run.

Solutions

  1. Run a YAML linter on config/profile.yml (`npx yaml-lint config/profile.yml` or paste into a YAML validator) to find the exact syntax error named in err.message.
  2. Fix the reported line — most often replace tabs with spaces, quote values containing ':' or '#', and correct indentation to consistent 2-space steps.
  3. If the file is beyond repair, restore from config/profile.example.yml and re-apply your settings, keeping valid YAML.
  4. Re-run the evaluation and confirm the warning no longer appears and the intended modes_dir is picked up.

Example fix

# before (config/profile.yml — invalid YAML, tab indentation)
language:
	output: de
	modes_dir: modes/de

# after
language:
  output: de
  modes_dir: modes/de
Defensive patterns

Strategy: try-catch

Validate before calling

import { readFileSync } from 'node:fs';
import { parse } from 'yaml';
try {
  parse(readFileSync('config/profile.yml', 'utf8'));
  console.log('config/profile.yml is valid YAML');
} catch (err) {
  console.error(`config/profile.yml invalid: ${err.message}`);
  process.exitCode = 1;
}

Try / catch

try {
  const profile = yaml.load(readFileSync('config/profile.yml', 'utf8'));
  // proceed
} catch (err) {
  console.warn(`Could not parse config/profile.yml: ${err.message}`);
  // fall back to defaults, and surface the message to the user so the file gets fixed
}

Prevention

When it happens

Trigger: config/profile.yml contains malformed YAML (bad indentation, tabs, unquoted special characters like ':' or '#' in values, duplicate keys in strict mode) or cannot be read (missing read permission); also thrown if yaml.load returns unexpected types that break property access inside the guarded block.

Common situations: Hand-editing profile.yml and breaking indentation or leaving a value like `modes_dir: modes/de #comment` with an odd character; pasting YAML from a doc with tabs instead of spaces; a partially written file after an interrupted edit; Windows line-ending or BOM issues in the file.

Related errors


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

Appendix: source

Thrown at gemini-eval.mjs:130

      if (rel.startsWith('..') || isAbsolute(customModesDir)) {
        console.warn(`⚠️   modes_dir "${customModesDir}" escapes project root; using default modes/`);
      } else {
        if (existsSync(dirPath)) {
          const candidateFiles = ['oferta.md', 'angebot.md', 'offre.md', 'kyujin.md', 'is-ilani.md', 'naukri.md'];
          const found = candidateFiles.find((file) => existsSync(join(dirPath, file)));
          if (found) {
            modesDir = customModesDir;
            evalFilename = found;
          } else {
            console.warn(`⚠️   No matching evaluation file found in ${customModesDir}; using default modes/oferta.md`);
          }
        } else {
          console.warn(`⚠️   modes_dir "${customModesDir}" not found; using default modes/`);
        }
      }
    }
  } catch (err) {
    console.warn(`⚠️   Could not parse config/profile.yml: ${err.message}`);
  }
}

PATHS.shared = join(CODE_ROOT, modesDir, '_shared.md');
PATHS.oferta = join(CODE_ROOT, modesDir, evalFilename);

// ---------------------------------------------------------------------------
// CLI argument parsing
// ---------------------------------------------------------------------------
const args = process.argv.slice(2);

if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
  console.log(`
╔══════════════════════════════════════════════════════════════════╗
║           career-ops — Gemini Evaluator (free-tier)             ║
╚══════════════════════════════════════════════════════════════════╝

  Evaluate a job offer using Google Gemini instead of Claude.

View on GitHub (pinned to aac998c7ed)