santifer/career-ops · error

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

Error message

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

What it means

The outer try in openai-tailor.mjs failed — either the mkdirSync/existence check for output/, the writeFileSync of the tailored HTML, or the filename-building code threw — and the process exits with code 1. The tailored CV was NOT saved anywhere. Common fs codes: EACCES (output/ not writable), ENOSPC (disk full), ENOENT (a path component vanished mid-run). Unlike most warnings in this codebase, this one is terminal for the run.

Source

Thrown at openai-tailor.mjs:347

  }
  candidateName = candidateName
    .toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');

  const filename = `cv-${candidateName}-${companySlug}.html`;
  const htmlPath = join(PATHS.output, filename);

  writeFileSync(htmlPath, tailoredHtml, 'utf-8');
  console.log(`\n✅  Tailored HTML saved: ${htmlPath}`);

  // Print next steps
  const pdfFilename = `cv-${candidateName}-${companySlug}-${roleSlug}-${new Date().toISOString().split('T')[0]}.pdf`;
  const reportNumMatch = reportFilename.match(/^(\d+)-/);
  const reportNum = reportNumMatch ? reportNumMatch[1] : '001';

  console.log(`\n📄  Next step (generate PDF):\n    node generate-pdf.mjs output/${filename} output/${pdfFilename} --format=letter --report=${reportNum}\n`);

} catch (err) {
  console.warn(`⚠️   Could not save HTML: ${err.message}`);
  process.exit(1);
}

View on GitHub (pinned to 60398d6549)

Solutions

  1. mkdir -p output && chmod u+w output, then re-run the tailor (the report it read still exists).
  2. Run df -h and free space if the error was ENOSPC.
  3. Verify output is a directory, not a stale file: ls -ld output.
  4. Treat the exit code 1 as 'nothing was written' — never assume partial output.

Example fix

// before
writeFileSync(htmlPath, tailoredHtml, 'utf-8');
} catch (err) {
  console.warn(`⚠️   Could not save HTML: ${err.message}`);
  process.exit(1);
}
// after — include path and code so the fatal exit is diagnosable
} catch (err) {
  console.error(`Could not save HTML to ${htmlPath}: ${err.code ?? err.name} — check output/ permissions and disk space`);
  process.exit(1);
}
Defensive patterns

Strategy: validation

Validate before calling

import { mkdirSync, accessSync, constants } from 'node:fs';
mkdirSync('output', { recursive: true });
accessSync('output', constants.W_OK); // fail BEFORE any model call if the target dir cannot take the file

Try / catch

catch (err) {
  console.error(`Could not save HTML to ${htmlPath}: ${err.code ?? err.message}`);
  process.exit(1);
} // exit non-zero so callers and CI know nothing was produced

Prevention

When it happens

Trigger: output/ is read-only or owned by another user (EACCES); disk full (ENOSPC); output/ deleted between the existence check and the write; PATHS.output pointing at an existing file rather than a directory.

Common situations: CI artifact cleanup racing the run; WSL/Docker permission mismatches; disk exhaustion after generating many CVs; a stray file named output blocking the directory.

Related errors


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