{"record":{"id":"c55691e19cf4910f","repo":"JuliusBrussee/caveman","slug":"caveman-sync-requires-node-22-13-it-reads-the","errorCode":null,"errorMessage":"caveman sync requires Node >= 22.13 (it reads the local spend store via node:sqlite); you are running Node ${process.versions.node}","messagePattern":"caveman sync requires Node >= 22\\.13 \\(it reads the local spend store via node:sqlite\\); you are running Node (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":9952,"sourceCode":"}\n\n// syncLocalSavings does one idempotent sync pass. It throws on transport or\n// server errors (the watermark is NOT advanced then) and returns an outcome\n// the callers turn into one honest line.\nasync function syncLocalSavings(cfg: Config): Promise<SyncOutcome> {\n  const dbPath = localSpendDbPath();\n  try {\n    statSync(dbPath);\n  } catch {\n    return { kind: \"no_store\", dbPath };\n  }\n  // node:sqlite is built into Node ≥22.13 — still zero runtime deps. Imported\n  // lazily so only sync paths ever load it (or pay its experimental warning).\n  let DatabaseSync: (typeof import(\"node:sqlite\"))[\"DatabaseSync\"];\n  try {\n    ({ DatabaseSync } = await import(\"node:sqlite\"));\n  } catch {\n    throw new Error(\n      `caveman sync requires Node >= 22.13 (it reads the local spend store via node:sqlite); you are running Node ${process.versions.node}`,\n    );\n  }\n  const db = new DatabaseSync(dbPath, { readOnly: true });\n  let rows: Record<string, unknown>[];\n  const key = syncWatermarkKey(cfg, dbFingerprint(db, dbPath, DatabaseSync));\n  const firstSync = !hasSyncWatermark(key);\n  const since = readSyncWatermark(key);\n  try {\n    const columns = new Set(\n      (db.prepare(\"PRAGMA table_info(requests)\").all() as Record<string, unknown>[])\n        .map((row) => typeof row.name === \"string\" ? row.name : \"\")\n        .filter(Boolean),\n    );\n    const optional = (name: string, fallback: string) => columns.has(name) ? name : `${fallback} AS ${name}`;\n    rows = db\n      .prepare(\n        `SELECT id, ts, request_id, trace_id, agent_slug, provider, model,","sourceCodeStart":9934,"sourceCodeEnd":9970,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L9934-L9970","documentation":"sync requires node:sqlite, which is built into Node >= 22.13. When the running Node is older, sync refuses with the installed version in the message instead of failing obscurely on the missing module.","triggerScenarios":"Thrown at packages/cli/src/index.ts:9107 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Upgrade Node to >= 22.13 (nvm install 22, nvm use 22)","Skip local savings sync on older Node"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}