santifer/career-ops · warning

⚠️ Could not save report: ${err.message}

Error message

⚠️   Could not save report: ${err.message}

What it means

Best-effort warning in gemini-eval.mjs's report-save phase: writing the report file to reports/ or the tracker-addition TSV to batch/tracker-additions/ failed, so evaluation output is not persisted and exitCode is set to 1. The original filesystem error (EACCES, ENOENT directory missing, invalid filename characters from the company slug, disk full) is appended to the message.

Source

Thrown at gemini-eval.mjs:441

      writeFileSync(reportPath, reportContent, 'utf-8');
      mkdirSync(PATHS.trackerAdditions, { recursive: true });
      const trackerFields = [
        String(parseInt(num, 10)),
        today,
        tsvSafe(company),
        tsvSafe(role),
        'Evaluated',
        normalizedTrackerScore(score),
        '❌',
        `[${num}](reports/${filename})`,
        'Gemini evaluation',
      ];
      writeFileSync(trackerPath, `${trackerFields.join('\t')}\n`, 'utf-8');
      console.log(`\n✅  Report saved: reports/${filename}`);
      console.log(`📊  Tracker addition saved: batch/tracker-additions/${num}-${companySlug}.tsv`);
      reportSaved = true;
    } catch (err) {
      console.warn(`⚠️   Could not save report: ${err.message}`);
      process.exitCode = 1;
    }

    if (reportSaved) {
      try {
        const mergeOutput = execFileSync(process.execPath, [join(ROOT, 'merge-tracker.mjs')], {
          cwd: ROOT,
          encoding: 'utf-8',
          stdio: ['ignore', 'pipe', 'pipe'],
        });
        if (mergeOutput.trim()) console.log(mergeOutput.trim());
        console.log('📊  Tracker merged into data/applications.md.');
      } catch (err) {
        console.warn(`⚠️   Report saved, but could not merge tracker addition into data/applications.md: ${err.message}`);
        process.exitCode = 1;
      }
    }
  } finally {

View on GitHub (pinned to 60398d6549)

Solutions

  1. Create the missing directories: `mkdir -p reports batch/tracker-additions`
  2. Check the appended errno in the message — EACCES means fix permissions, ENOSPC means free space
  3. Re-run the evaluation (the reservation is released in finally, so the report number is not leaked)
  4. If the company name is the problem, sanitize or manually add the entry per the tracker TSV conventions

Example fix

# before
node gemini-eval.mjs "<jd>"   # reports/ absent -> Could not save report: ENOENT
# after
mkdir -p reports batch/tracker-additions && node gemini-eval.mjs "<jd>"
Defensive patterns

Strategy: try-catch

Validate before calling

import { accessSync, constants, mkdirSync } from 'node:fs';
for (const dir of ['reports', 'batch/tracker-additions']) {
  mkdirSync(dir, { recursive: true });
  accessSync(dir, constants.W_OK); // throws early with a clear EACCES instead of mid-eval
}

Try / catch

try {
  saveReport();
} catch (err) {
  if (['ENOENT', 'EACCES', 'ENOSPC'].includes(err.code)) {
    // report did not persist: fix fs issue, re-run evaluation; reservation is released in finally
    console.error(`report not saved (${err.code}); safe to re-run`);
    process.exitCode = 1;
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Running gemini-eval when reports/ or batch/tracker-additions/ does not exist or is read-only; a company name whose slug produces an illegal filename on the filesystem; ENOSPC. The catch keeps going to the finally block that releases reserved report numbers.

Common situations: Fresh or partial clones missing gitignored output dirs; running as a user without write permission to the repo; exotic characters (slashes, colons on Windows) in the scraped company name; full disks in containers.

Related errors


AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20). Data as JSON: /api/errors/78e262ecf818177f. Report an issue: GitHub.