santifer/career-ops · warning

node:sqlite unavailable (Node < 22.5) — tracker index tests…

Error message

node:sqlite unavailable (Node < 22.5) — tracker index tests skipped

What it means

Section 15 of test-all.mjs tests the tracker's derived SQLite index; it first probes `import('node:sqlite')` in a child Node process. node:sqlite is only available from Node 22.5+, so on older runtimes the probe exits non-zero and the test warns that tracker index tests are skipped rather than failing.

Solutions

  1. Upgrade Node to >= 22.5 (nvm install 22 && nvm use 22) so the index tests run.
  2. Pin a modern Node in CI (actions/setup-node with node-version: '22').
  3. Accept the skip on older Node — the tests are additive coverage, not a correctness gate for the rest of the suite.
  4. If you need this test but cannot upgrade, run just section 15 under a Node 22+ binary by pointing NODE at it.

Example fix

// before (CI)
- uses: actions/setup-node@v4
  with: { node-version: '20' }
// after
  with: { node-version: '22' }
Defensive patterns

Strategy: fallback

Validate before calling

let sqliteOk = false; try { await import('node:sqlite'); sqliteOk = true; } catch {} if (!sqliteOk) console.warn('Node >= 22.5 required for tracker index tests');

Type guard

const supportsNodeSqlite = (v) => { const [maj, min] = v.split('.').map(Number); return maj > 22 || (maj === 22 && min >= 5); };

Try / catch

const available = run(NODE, ['--no-warnings', '-e', "import('node:sqlite').then(()=>process.exit(0),()=>process.exit(1))"]) !== null; if (!available) warn('node:sqlite unavailable — skipping index tests');

Prevention

When it happens

Trigger: `run(NODE, ['--no-warnings', '-e', "import('node:sqlite').then(()=>process.exit(0),()=>process.exit(1))"])` returns null because the active Node is < 22.5 (or a build without the sqlite module), making sqliteAvailable false.

Common situations: CI matrices pinned to Node 20 LTS, contributors with system Node 18/20, nvm pointing at an older default, or Docker images based on node:20.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at test-all.mjs:13119

  } else {
    fail('AGENTS.md misses onboarding state docs or CLAUDE.md is not a thin wrapper');
  }
} catch (e) {
  fail(`Cold-start trigger test crashed: ${e.message}`);
}

// ── 15. TRACKER DERIVED INDEX (#918 phase 1) ────────────────────
// applications.md is the source of truth; applications.db is a derived index
// rebuilt from it. Round-trip md → db → md must be lossless for clean input
// (a hard condition from #918 before any phase-2 work), sync must DETECT
// corruption without ever modifying the markdown, and reads must never be
// stale.

console.log('\n15. Tracker derived index (sync/query/export round-trip)');

const sqliteAvailable = run(NODE, ['--no-warnings', '-e', "import('node:sqlite').then(()=>process.exit(0),()=>process.exit(1))"]) !== null;
if (!sqliteAvailable) {
  warn('node:sqlite unavailable (Node < 22.5) — tracker index tests skipped');
} else {
  try {
    const idxTmp = mkdtempSync(join(tmpdir(), 'career-ops-index-'));
    try {
      const md = join(idxTmp, 'applications.md');
      const env = { ...process.env, CAREER_OPS_TRACKER: md };
      const trackerRun = (args) => run(NODE, ['tracker.mjs', ...args], { env, stdio: ['pipe', 'pipe', 'pipe'] });

      // 1. Round trip: clean canonical input must export byte-identical.
      const clean =
        '# Applications Tracker\n\n' +
        '| # | Date | Company | Role | Score | Status | PDF | Report | Notes |\n' +
        '|---|------|---------|------|-------|--------|-----|--------|-------|\n' +
        '| 2 | 2026-01-05 | Beta | Designer | 4.0/5 | Applied | ✅ | [2](../reports/002-beta-2026-01-05.md) | second |\n' +
        '| 1 | 2026-01-04 | Acme | Engineer | 4.2/5 | Evaluated | ❌ | [1](../reports/001-acme-2026-01-04.md) | first |\n';
      writeFileSync(md, clean);
      if (trackerRun(['sync']) === null) {
        fail('tracker sync crashed on clean fixture');

View on GitHub (pinned to e7abd431fc)