ruvnet/ruflo · error · Error
KV cache file missing SHA256 footer
Error message
KV cache file missing SHA256 footer
What it means
Thrown by loadKvCache after the entry loop when offset + 32 > data.length — the file has no room for the mandatory 32-byte SHA-256 footer. The footer is the integrity check for all entry data, so its absence means the file is incomplete or was not produced by a conformant writer.
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 6b01dc5a68)
Solutions
- Regenerate the cache with persistKvCache and confirm it completes (atomic write-then-rename prevents half-footers).
- Delete the footerless file and cold-start.
- Treat missing-footer as recoverable in loadKvCache's caller (catch and continue without cache).
- Verify no external process (backup/cleanup agent) is truncating cache files.
Example fix
// before
await engine.loadKvCache(path);
// after
try {
await engine.loadKvCache(path);
} catch (e) {
if (e instanceof Error && /missing SHA256 footer/.test(e.message)) {
logger.warn({ path }, 'KV cache missing footer; regenerating');
await fsUnlink(path).catch(() => {});
} else throw e;
} Defensive patterns
Strategy: fallback
Validate before calling
// Ensure the file has room for the 32-byte footer:
const data = await readFile(path);
if (data.length < 44 + 32) {
await fsUnlink(path).catch(() => {});
return; // cannot contain header + footer
}
await engine.loadKvCache(path); Type guard
function hasRoomForFooter(size: number): boolean {
return size >= 44 + 32;
} Try / catch
try {
await engine.loadKvCache(path);
} catch (e) {
if (e instanceof Error && /missing SHA256 footer/.test(e.message)) {
await fsUnlink(path).catch(() => {});
return;
}
throw e;
} Prevention
- Atomic writes guarantee the footer lands.
- Regenerate caches missing a footer.
- Confirm no external process trims cache files.
- Cold-start on missing footer.
When it happens
Trigger: All declared entries were consumed but the file ends without the trailing 32-byte SHA-256 digest — e.g. persistKvCache was interrupted after writing entries but before (or during) the footer, or the file was trimmed by an external process.
Common situations: Crash during the final Buffer.concat/write of persistKvCache (footer is the last component); a tool that stripped trailing bytes; a cache written by an older writer that did not emit a footer (in which case version mismatch would normally fire first).
Related errors
- KV cache integrity check failed: hash mismatch
- 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/da8f9952fcd8ce70.
Report an issue: GitHub.