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
- Upgrade Node to >= 22.5 (nvm install 22 && nvm use 22) so the index tests run.
- Pin a modern Node in CI (actions/setup-node with node-version: '22').
- Accept the skip on older Node — the tests are additive coverage, not a correctness gate for the rest of the suite.
- 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
- Use Node >= 22.5 for full test coverage (nvm install 22)
- Pin node-version: 22 in CI matrices
- Gate sqlite-dependent features on a runtime capability probe, not a version string
- Document the minimum Node version in the README
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
- archive render skipped — no Playwright browser in env
- Cannot import generate-pdf.mjs
- concurrent reservation test flaked
- Dashboard build skipped — go compiler not in env
- H1B_INDEX_PATH is set but empty. Unset it to use the…
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)