ruvnet/ruflo · error · Error

KV cache file too small

Error message

KV cache file too small

What it means

Thrown by loadKvCache when the loaded file is shorter than 44 bytes. The RVKV format header alone is 44 bytes (4 magic + 4 version + 32 model hash + 4 entry count), so anything smaller cannot even contain a valid header. This is the first integrity gate on cache files.

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 6b01dc5a68)

Solutions

  1. Check the file size and mtime before loading; if it is < 44 bytes or zero bytes, delete it and regenerate via persistKvCache.
  2. Ensure persistKvCache completed successfully in a prior run (look for the success log line and a non-trivial file size).
  3. Confirm loadKvCache is pointed at a file previously produced by persistKvCache of the same engine, not an arbitrary path.
  4. Wrap loadKvCache so a missing/corrupt cache falls back to a cold start instead of crashing.

Example fix

// before
await engine.loadKvCache(path);

// after
const stat = await fsStat(path);
if (stat.size < 44) {
  logger.warn({ path, size: stat.size }, 'KV cache too small; starting cold');
  await fsUnlink(path).catch(() => {});
} else {
  await engine.loadKvCache(path);
}
Defensive patterns

Strategy: validation

Validate before calling

const stat = await fsStat(path);
if (stat.size < 44) {
  logger.warn({ path, size: stat.size }, 'KV cache below minimum header size');
  await fsUnlink(path).catch(() => {});
  return; // cold start
}
await engine.loadKvCache(path);

Type guard

function meetsMinHeaderSize(size: number): boolean {
  return size >= 44;
}

Try / catch

try {
  await engine.loadKvCache(path);
} catch (e) {
  if (e instanceof Error && /file too small/.test(e.message)) {
    await fsUnlink(path).catch(() => {});
    return; // cold start
  }
  throw e;
}

Prevention

When it happens

Trigger: Loading an empty file, a near-empty file, or a path that points to a different/tiny artifact. readFileSync succeeds (no ENOENT) but the buffer is below the minimum header size.

Common situations: An interrupted persistKvCache left a zero-byte file behind; pointing loadKvCache at a placeholder/pid file or a totally different format; the cache path was never written to because persistKvCache failed earlier.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/c2558ce168f737c5. Report an issue: GitHub.