{"record":{"id":"da8f9952fcd8ce70","repo":"ruvnet/ruflo","slug":"kv-cache-file-missing-sha256-footer","errorCode":null,"errorMessage":"KV cache file missing SHA256 footer","messagePattern":"KV cache file missing SHA256 footer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/appliance/gguf-engine.ts","lineNumber":412,"sourceCode":"    if (version !== RVKV_VERSION) throw new Error(`Unsupported KV cache version: ${version}`);\n\n    const entryCount = data.readUInt32LE(40);\n    let offset = 44;\n    const entries = new Map<string, Buffer>();\n\n    for (let i = 0; i < entryCount; i++) {\n      if (offset + 8 > data.length) throw new Error('KV cache file truncated');\n      const keyLen = data.readUInt32LE(offset);\n      const valLen = data.readUInt32LE(offset + 4);\n      offset += 8;\n      if (offset + keyLen + valLen > data.length) throw new Error('KV cache file truncated');\n      entries.set(data.toString('utf-8', offset, offset + keyLen), Buffer.from(data.subarray(offset + keyLen, offset + keyLen + valLen)));\n      offset += keyLen + valLen;\n    }\n\n    // Verify footer hash (mandatory)\n    if (offset + 32 > data.length) {\n      throw new Error('KV cache file missing SHA256 footer');\n    }\n    const stored = data.subarray(offset, offset + 32);\n    const computed = createHash('sha256').update(data.subarray(44, offset)).digest();\n    if (!stored.equals(computed)) throw new Error('KV cache integrity check failed: hash mismatch');\n\n    this.kvCache = entries;\n    if (this.config.verbose) console.log(`[gguf-engine] KV cache loaded: ${entries.size} entries`);\n  }\n\n  /** Return metadata for all loaded models. */\n  getLoadedModels(): GgufMetadata[] { return Array.from(this.loadedModels.values()); }\n\n  /** Store a key-value pair in the in-memory KV cache. */\n  setKvEntry(key: string, value: Buffer): void { this.kvCache.set(key, value); }\n\n  /** Retrieve a key-value pair from the in-memory KV cache. */\n  getKvEntry(key: string): Buffer | undefined { return this.kvCache.get(key); }\n","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/appliance/gguf-engine.ts#L394-L430","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { stat, rm } from 'node:fs/promises';\n// A complete RVKV file is at least 44B header + 0 entries + 32B footer = 76B\nconst st = await stat(kvCachePath).catch(() => null);\nif (!st || st.size < 76) {\n  await rm(kvCachePath, { force: true }); // cannot possibly contain header + footer\n}","typeGuard":null,"tryCatchPattern":"try {\n  await engine.loadKvCache(kvCachePath);\n} catch (err) {\n  if (err instanceof Error && err.message === 'KV cache file missing SHA256 footer') {\n    await rm(kvCachePath, { force: true }); // regenerate from live state\n  } else {\n    throw err;\n  }\n}","preventionTips":["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"],"tags":["gguf-engine","kv-cache","sha256","binary-format","file-corruption"],"backgroundTag":"truncated-binary-file","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}