ruvnet/ruflo · error
Unsupported KV cache version
Error message
Unsupported KV cache version: ${version} What it means
Bytes 4-8 of the cache file hold the format version, and only RVKV_VERSION (currently 1) is accepted; anything else throws. The cache was written by an engine build with a different RVKV layout, so its entries cannot be trusted and loading stops rather than misreading the structure.
Solutions
- Delete the stale cache and re-persist with the current engine — KV caches are rebuildable by design
- Pin one CLI version across nodes that share a cache volume, or namespace cache paths per version
- Catch the error and fall back to a cold cache instead of failing generation
Example fix
// before
await engine.loadKvCache(cachePath);
// after
try {
await engine.loadKvCache(cachePath);
} catch {
await rm(cachePath, { force: true });
await engine.persistKvCache(cachePath); // rebuild cold
} Defensive patterns
Strategy: fallback
Validate before calling
const fh = await open(cachePath, 'r');
const b = Buffer.alloc(8);
await fh.read(b, 0, 8, 0); await fh.close();
const version = b.readUInt32LE(4);
if (b.toString('ascii', 0, 4) !== 'RVKV' || version !== 1) {
await engine.persistKvCache(cachePath); // rebuild cold cache
} else {
await engine.loadKvCache(cachePath);
} Try / catch
try { await engine.loadKvCache(cachePath); }
catch (e) {
if (e instanceof Error && e.message.includes('Unsupported KV cache version')) {
await rm(cachePath, { force: true });
await engine.persistKvCache(cachePath); // cold start
} else throw e;
} Prevention
- Namespace cache paths by CLI/engine version on shared volumes
- Treat an unreadable cache as a cold start, never a fatal error
- Delete stale caches as part of upgrade/runbook steps
When it happens
Trigger: Loading a cache persisted by a different @claude-flow/cli version after an upgrade or downgrade; hand-crafted cache files; caches left in a shared volume by a previous deployment.
Common situations: Rolling upgrades across a format change; pinned older CLI images reading newer caches; volume mounts reused between appliance generations.
Related errors
- Invalid KV cache magic: 0x
- Unsupported GGUF version
- Invalid GGUF magic: 0x
- KV cache file too small
- KV cache file truncated
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/11db87323ea87ff4.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:394
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;
}
// Verify footer hash (mandatory)
if (offset + 32 > data.length) {
throw new Error('KV cache file missing SHA256 footer');View on GitHub (pinned to fa13ee4ad6)