ruvnet/ruflo · error
KV cache file missing SHA256 footer
Error message
KV cache file missing SHA256 footer
What it means
After loadKvCache() consumes all entryCount entries it requires 32 more bytes of mandatory SHA-256 footer (`offset + 32 > data.length` fails). This error means the entries parsed cleanly but the file ends with fewer than 32 bytes remaining — i.e. the integrity footer is absent. Like error 120 it indicates a file cut off mid-write or truncated after the entry region.
Solutions
- Delete the cache file and let the engine regenerate it from live state
- If restoring from a backup or copy, re-copy and verify the byte size matches the original
- Check whether any tool (log rotation, sync daemon) truncates or rewrites the cache path
- Switch persistence to an atomic write (temp file + rename) so a footer-less file can never be observed
Defensive patterns
Strategy: try-catch
Validate before calling
import { stat, rm } from 'node:fs/promises';
// A complete RVKV file is at least 44B header + 0 entries + 32B footer = 76B
const st = await stat(kvCachePath).catch(() => null);
if (!st || st.size < 76) {
await rm(kvCachePath, { force: true }); // cannot possibly contain header + footer
} Try / catch
try {
await engine.loadKvCache(kvCachePath);
} catch (err) {
if (err instanceof Error && err.message === 'KV cache file missing SHA256 footer') {
await rm(kvCachePath, { force: true }); // regenerate from live state
} else {
throw err;
}
} Prevention
- Regenerate-on-corruption: cache files are derived state, never repair them
- Use atomic writes (temp + rename) so a footer-less file is never observable
- Keep a single writer per cache path and exclude cache files from sync/rotation tools that truncate
When it happens
Trigger: `engine.loadKvCache(path)` on a file truncated by exactly the footer (or more), a hand-assembled cache written without the 32-byte SHA-256 footer, or a partially synced/copied file whose tail is missing.
Common situations: Crash during persistKvCache's single writeFile call; partial file copy; a sync/rotation tool that truncated the cache path; a custom script that rewrote cache entries but forgot to append the hash footer.
Related errors
- KV cache integrity check failed: hash mismatch
- Buffer too small for declared header
- Buffer too small for RVFP preamble
- Buffer too small to contain declared header
- Buffer too small to contain RVFA preamble
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/da8f9952fcd8ce70.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:412
if (version !== RVKV_VERSION) throw new Error(`Unsupported KV cache version: ${version}`);
const entryCount = data.readUInt32LE(40);
let offset = 44;
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); }
View on GitHub (pinned to fa13ee4ad6)