JuliusBrussee/caveman · error · Error
sync incomplete — ${failures.join("; ")}
Error message
sync incomplete — ${failures.join("; ")} What it means
Thrown by the CLI's explicit sync path after it fans local-state uploads out into parallel lanes (practice findings, local scan) using allSettled-style handling. Each rejected lane appends a human-readable '<lane>: <reason>' string; if any lane failed, one aggregated error is thrown so partial success is never reported as a complete sync. The nearby syncAfterLogin helper deliberately does NOT throw (best-effort after login), so hitting this message means the user-invoked sync command ran.
Source
Thrown at packages/cli/src/index.ts:10150
if (out.firstSync) console.log(SYNC_DISCLOSURE);
console.log(syncSavingsLine(out));
}
} else {
failures.push(`local spans: ${syncLaneError(savingsLane.reason)}`);
}
if (practicesLane.status === "fulfilled") {
if (practicesLane.value.kind === "synced") {
console.log(`synced ${practicesLane.value.findings} local practice findings · basis: inferred (tokens only; no payload evidence)`);
}
} else {
failures.push(`practice findings: ${syncLaneError(practicesLane.reason)}`);
}
if (localScanLane.status === "fulfilled") {
if (localScanLane.value.kind === "synced") console.log(localScanSyncLine(localScanLane.value));
} else {
failures.push(`local scan: ${syncLaneError(localScanLane.reason)}`);
}
if (failures.length > 0) throw new Error(`sync incomplete — ${failures.join("; ")}`);
}
function syncLaneError(reason: unknown): string {
return reason instanceof Error ? reason.message : String(reason);
}
// syncAfterLogin runs the same sync once right after a successful login so the
// dashboard immediately shows what the local proxy already measured. Strictly
// best-effort: a sync failure never fails the login.
async function syncAfterLogin() {
try {
const cfg = await config();
if (!cfg.token) return;
const [savingsLane, practicesLane, localScanLane] = await Promise.allSettled([
syncLocalSavings(cfg),
syncLocalPracticeFindings(cfg),
syncPendingLocalScan(cfg),
] as const);View on GitHub (pinned to 5184b3d11a)
Solutions
- Read the joined lane reasons to identify which sync failed (practice findings vs local scan) before changing anything
- Verify the local proxy is running and healthy (e.g. `caveman status` or its stats endpoint)
- Run `caveman setup` to confirm engine/proxy binaries resolve; set CAVEMAN_ENGINE_BIN if the engine lives elsewhere
- If a lane reason mentions 401/403 or token expiry, re-run `caveman login` and retry
- Re-run the sync — lane failures caused by transient network errors usually clear on retry
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight the lanes' shared dependency so transient sync failures never start.
import { spawnSync } from 'node:child_process';
const probe = spawnSync(process.env.CAVEMAN_ENGINE_BIN ?? 'caveman-engine', ['--version']);
if (probe.error) throw new Error(`engine missing: ${String(probe.error.message)}`); Try / catch
try {
await runSync();
} catch (e) {
const msg = (e as Error).message;
if (msg.startsWith('sync incomplete')) {
// lane names + reasons are '; '-joined — retry only the failed lanes, or the whole sync once
} else throw e;
} Prevention
- Start the local proxy and confirm it is healthy before invoking sync
- Run `caveman setup` on new machines so engine/proxy binaries exist
- Treat sync as best-effort in pipelines: catch the aggregate error, log lane reasons, and do not fail the build on it
When it happens
Trigger: Running the sync command when at least one lane rejects: the local proxy/engine subprocess exits non-zero, the proxy is not running or not listening, the engine binary is missing from PATH/CAVEMAN_ENGINE_BIN, or the cloud API call fails on auth or network. The message enumerates every failed lane joined by '; '.
Common situations: Fresh machine that never ran `caveman setup` (engine/proxy binaries absent), proxy daemon stopped or crashed mid-run, expired or rotated auth token, transient network loss during upload, version skew between CLI and local proxy.
Related errors
- invalid Decision Ledger response
- recent stats was not a JSON array
- cave_stale_lock:${checked.stale.join(",")}: run npm run buil
- caveman agent: Cave Runtime failed to start (${error instanc
- caveman agent: Cave Runtime did not become ready at ${gatewa
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-08-18).
Data as JSON: /api/errors/c85b8a36df7051f0.
Report an issue: GitHub.