JuliusBrussee/caveman · error · Error
result.error?.message ?? `local scan sync failed
Error message
result.error?.message ?? `local scan sync failed (${response.status})` What it means
Thrown when a local-scan sync POST completes but the response does not describe a successful delivery: either the server returned an error body (its `error.message` is surfaced) or the payload failed shape checks (status must be "completed", source "local_scan", basis "inferred", and a non-empty string `id`). It signals the sync import was not accepted.
Solutions
- Read the surfaced `error.message` from the response body shown in the thrown error for the server's reason.
- Verify CLI and gateway versions are compatible (response contract: status=completed, source=local_scan, basis=inferred).
- Check that the target project exists and the scan payload passes server validation.
- If a proxy interferes, hit the gateway directly and inspect the raw response.
Example fix
// before: stale CLI expecting old response shape
throw new Error(result.error?.message ?? `local scan sync failed (${response.status})`)
// after: upgrade CLI to match current gateway response contract
npm i -g @caveman/cli@latest && caveman sync Defensive patterns
Strategy: validation
Validate before calling
// Validate the expected response contract before treating sync as done
function isDelivered(r) {
return r && r.status === "completed" && r.source === "local_scan" &&
r.basis === "inferred" && typeof r.id === "string" && r.id.length > 0;
} Type guard
function isSyncResult(v: unknown): v is { status: "completed"; source: "local_scan"; basis: "inferred"; id: string; project_id?: string } {
const r = v as Record<string, unknown>;
return r.status === "completed" && r.source === "local_scan" &&
r.basis === "inferred" && typeof r.id === "string" && r.id.length > 0;
} Try / catch
try {
await syncLocalScan();
} catch (e) {
console.error(`Local scan sync rejected: ${e.message}`); // server error.message is surfaced first
// inspect CLI/gateway version compatibility, then retry after fixing
} Prevention
- Keep CLI and gateway versions in sync — response shape is versioned.
- Confirm the target project exists and the scan payload passes server validation.
- Check the surfaced error.message before assuming a client bug.
When it happens
Trigger: Syncing local scan results when the server rejects the payload (validation error), returns a non-completed status, or responds with an unexpected JSON shape missing `id`/`project_id`.
Common situations: Gateway version mismatch where the response schema changed (e.g. source/basis values differ); server-side validation rejecting the scan batch; proxy returning an HTML error page parsed as {}; project not provisioned server-side.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- result.error?.message ?? `sync import failed
- cave_request_failed
- cave request failed ( )
- caveman: remote gateway key revocation failed
- caveman: remote session revocation failed
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/80c43cb8fa10bec4.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:10226
body: JSON.stringify(state.payload),
});
const result = (await response.json().catch(() => ({}))) as {
id?: string;
project_id?: string;
status?: string;
source?: string;
basis?: string;
error?: { message?: string };
};
if (
!response.ok
|| result.status !== "completed"
|| result.source !== "local_scan"
|| result.basis !== "inferred"
|| typeof result.id !== "string"
|| !result.id
) {
throw new Error(result.error?.message ?? `local scan sync failed (${response.status})`);
}
const delivered: LocalScanState = {
...state,
delivered: {
import_id: result.id,
project_id: typeof result.project_id === "string" ? result.project_id : cfg.projectId ?? "",
organization_id: cfg.organizationId ?? "",
base_url: cfg.baseURL,
delivered_at: new Date().toISOString(),
},
};
mkdirSync(dirname(localScanStatePath()), { recursive: true });
writeFileSync(localScanStatePath(), JSON.stringify(delivered, null, 2) + "\n", { mode: 0o600 });
return { kind: "synced", importId: result.id, dashboard: deriveLocalScanDashboardUrl(cfg.baseURL) };
}
function localScanSyncLine(out: Extract<LocalScanSyncOutcome, { kind: "synced" }>): string {
const destination = out.dashboard ? ` → ${out.dashboard}` : "";View on GitHub (pinned to 3ee70a1026)