ruvnet/ruflo · error · Error
KV cache integrity check failed: hash mismatch
Error message
KV cache integrity check failed: hash mismatch
What it means
Thrown by loadKvCache when the stored 32-byte footer does not equal the SHA-256 computed over data.subarray(44, offset) (the entry region). This is the strongest integrity check: the cache content has been altered, truncated, extended, or corrupted after persistKvCache wrote it. A mismatch means the entries cannot be trusted.
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 6b01dc5a68)
Solutions
- Delete the corrupt cache and regenerate via persistKvCache (KV caches are disposable derived data).
- Ensure only one engine instance writes a given cache path; serialize or namespace caches per model/instance.
- Verify file transfer integrity (compare checksums) when moving caches between machines.
- If this reproduces on freshly written files, suspect the persistKvCache buffer-concatenation/hash scope and file a bug; do not weaken the integrity check.
Example fix
// before
await engine.loadKvCache(path);
// after
try {
await engine.loadKvCache(path);
} catch (e) {
if (e instanceof Error && /integrity check failed/.test(e.message)) {
logger.error({ path }, 'KV cache hash mismatch; discarding');
await fsUnlink(path).catch(() => {});
} else throw e;
} Defensive patterns
Strategy: fallback
Validate before calling
// The engine already computes and compares the hash. Callers cannot cheaply // pre-verify faster than the engine; instead, treat mismatch as disposable: // delete and regenerate. (See tryCatchPattern.)
Type guard
// No caller-side type guard; integrity is verified inside loadKvCache.
Try / catch
try {
await engine.loadKvCache(path);
} catch (e) {
if (e instanceof Error && /integrity check failed/.test(e.message)) {
logger.error({ path }, 'KV cache hash mismatch; discarding');
await fsUnlink(path).catch(() => {});
return;
}
throw e;
} Prevention
- Never weaken or skip the SHA-256 check.
- Ensure only one writer per cache path.
- Verify checksums when transferring caches between hosts.
- Discard and rebuild on any hash mismatch.
When it happens
Trigger: Any modification to the entry bytes between offset 44 and the footer without recomputing the footer — manual editing, disk corruption, a partial overwrite, or two writers racing on the same path. Also fires if the persistKvCache logic itself produced inconsistent header/footer (a bug), but on-disk mutation is far more common.
Common situations: Disk/filesystem corruption; two processes writing the same cache path concurrently; a cache copied between systems with a transfer that altered bytes; an older/newer writer with a different hash scope (version mismatch usually precedes this). The check is mandatory, so there is no bypass.
Related errors
- KV cache file missing SHA256 footer
- KV cache file too small
- Invalid KV cache magic: 0x${magic.toString(16)}
- KV cache file truncated
- No KV cache output path specified
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/fc50495825ce1855.
Report an issue: GitHub.