ruvnet/ruflo · error
KV cache integrity check failed: hash mismatch
Error message
KV cache integrity check failed: hash mismatch
What it means
The RVKV format ends with SHA-256 over bytes 44..offset (all entry data); loadKvCache() recomputes it and compares to the stored footer. A mismatch means the file is structurally complete but its content hash differs — silent corruption after write (bit rot, torn write from a concurrent writer) or tampering. This is the integrity check that catches damage errors 120/121 miss.
Solutions
- Delete the cache file and let it regenerate — do not attempt repair
- Ensure exactly one process/engine instance writes a given kvCachePath
- Persist atomically (temp file + rename) to eliminate torn writes
- If mismatches persist across fresh regenerations, suspect the storage medium or the transfer channel
Defensive patterns
Strategy: try-catch
Try / catch
try {
await engine.loadKvCache(kvCachePath);
} catch (err) {
if (err instanceof Error && err.message.startsWith('KV cache integrity check failed')) {
await rm(kvCachePath, { force: true }); // content hash mismatch — drop and rebuild
} else {
throw err;
}
} Prevention
- Allow exactly one writer per kvCachePath to avoid interleaved writes
- Persist atomically (temp file + rename) so torn writes cannot pass structural parsing but fail hashing
- Verify integrity right after persisting if caches are shipped across machines
When it happens
Trigger: `engine.loadKvCache(path)` on a structurally valid file where `stored.equals(computed)` is false — e.g. one flipped byte in the entry region, two engine instances writing the same kvCachePath concurrently (interleaved writes), or a transfer channel that mangles bytes (FTP ASCII mode).
Common situations: Multiple processes persisting KV caches to one path; failing storage media; manual binary edits; caches copied through a byte-mangling transport.
Related errors
- KV cache file missing SHA256 footer
- frozen human eval hash mismatch — set has drifted
- must be a canonical sha256 digest
- project flywheel anchor hash mismatch
- sha256 mismatch for : expected …, got …
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/fc50495825ce1855.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:416
const entries = new Map<string, Buffer>();
for (let i = 0; i < entryCount; i++) {
if (offset + 8 > data.length) throw new Error('KV cache file truncated');
const keyLen = data.readUInt32LE(offset);
const valLen = data.readUInt32LE(offset + 4);
offset += 8;
if (offset + keyLen + valLen > data.length) throw new Error('KV cache file truncated');
entries.set(data.toString('utf-8', offset, offset + keyLen), Buffer.from(data.subarray(offset + keyLen, offset + keyLen + valLen)));
offset += keyLen + valLen;
}
// Verify footer hash (mandatory)
if (offset + 32 > data.length) {
throw new Error('KV cache file missing SHA256 footer');
}
const stored = data.subarray(offset, offset + 32);
const computed = createHash('sha256').update(data.subarray(44, offset)).digest();
if (!stored.equals(computed)) throw new Error('KV cache integrity check failed: hash mismatch');
this.kvCache = entries;
if (this.config.verbose) console.log(`[gguf-engine] KV cache loaded: ${entries.size} entries`);
}
/** Return metadata for all loaded models. */
getLoadedModels(): GgufMetadata[] { return Array.from(this.loadedModels.values()); }
/** Store a key-value pair in the in-memory KV cache. */
setKvEntry(key: string, value: Buffer): void { this.kvCache.set(key, value); }
/** Retrieve a key-value pair from the in-memory KV cache. */
getKvEntry(key: string): Buffer | undefined { return this.kvCache.get(key); }
/** Release resources, unload models, and optionally persist the KV cache. */
async shutdown(): Promise<void> {
if (this.config.kvCachePath && this.kvCache.size > 0) {
try { await this.persistKvCache(this.config.kvCachePath); }View on GitHub (pinned to fa13ee4ad6)