ruvnet/ruflo · error
KV cache file too small
Error message
KV cache file too small
What it means
loadKvCache requires at least the 44-byte RVKV header (magic u32 + version u32 + 32-byte model SHA-256 + entry-count u32); a shorter file is rejected before any parsing. In practice the file is empty or nearly empty — the result of a failed/interrupted persist or a wrong path.
Solutions
- Stat the file first and require size >= 44 before loading; regenerate otherwise
- Delete the bad cache and re-persist with persistKvCache — the cache is disposable state
- Make persistence atomic (write temp file, then rename) so partial files never appear at the canonical path
Example fix
// before
await engine.loadKvCache(cachePath);
// after
const { size } = await stat(cachePath);
if (size < 44) {
await engine.persistKvCache(cachePath); // rebuild cold cache
} else {
await engine.loadKvCache(cachePath);
} Defensive patterns
Strategy: validation
Validate before calling
const { size } = await stat(cachePath);
if (size < 44) {
await engine.persistKvCache(cachePath); // rebuild: header alone is 44 bytes
} else {
await engine.loadKvCache(cachePath);
} Try / catch
try { await engine.loadKvCache(cachePath); }
catch (e) { if (e instanceof Error && e.message === 'KV cache file too small') { await engine.persistKvCache(cachePath); } else throw e; } Prevention
- Write caches atomically (temp file + rename) so partial files never exist at the load path
- Stat cache files before loading and regenerate undersized ones
- Treat KV caches as disposable: losing one costs only a warm-up
When it happens
Trigger: loadKvCache on a 0-43 byte file: an empty artifact left by a crashed persistKvCache, a partially copied cache, or a path pointing at some other tiny file.
Common situations: Hard-killed processes between file creation and write completion; non-atomic copies of live caches; path typos landing on unrelated small files.
Related errors
- KV cache file truncated
- String length exceeds remaining buffer
- Invalid KV cache magic: 0x
- No KV cache output path specified
- Unknown GGUF array element type
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/c2558ce168f737c5.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:389
entryBufs.push(hdr, keyBuf, value);
}
const entryData = Buffer.concat(entryBufs);
const footer = createHash('sha256').update(entryData).digest();
const header = Buffer.alloc(44);
header.writeUInt32LE(RVKV_MAGIC, 0);
header.writeUInt32LE(RVKV_VERSION, 4);
modelHash.copy(header, 8);
header.writeUInt32LE(this.kvCache.size, 40);
await writeFile(path, Buffer.concat([header, entryData, footer]));
if (this.config.verbose) console.log(`[gguf-engine] KV cache persisted: ${this.kvCache.size} entries`);
}
/** Restore KV cache from an RVF-compatible binary file. */
async loadKvCache(inputPath: string): Promise<void> {
const data = await readFile(inputPath);
if (data.length < 44) throw new Error('KV cache file too small');
const magic = data.readUInt32LE(0);
if (magic !== RVKV_MAGIC) throw new Error(`Invalid KV cache magic: 0x${magic.toString(16)}`);
const version = data.readUInt32LE(4);
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;View on GitHub (pinned to fa13ee4ad6)