ruvnet/ruflo · error

No KV cache output path specified

Error message

No KV cache output path specified

What it means

GgufEngine.persistKvCache(outputPath) writes the RVF binary only when outputPath is truthy or the engine was constructed with config.kvCachePath; both empty throws. The output location is never inferred, so persisting requires an explicit argument or config value.

Solutions

  1. Pass an explicit output path: await engine.persistKvCache('/cache/session.rvkv')
  2. Or set kvCachePath in GgufEngineConfig when constructing the engine
  3. Fail fast at startup: if KV persistence is enabled, require a non-empty kvCachePath before running

Example fix

// before
const engine = new GgufEngine({ contextSize: 2048 });
await engine.persistKvCache(''); // throws

// after
const engine = new GgufEngine({ contextSize: 2048, kvCachePath: '/cache/session.rvkv' });
await engine.persistKvCache('/cache/session.rvkv');
Defensive patterns

Strategy: validation

Validate before calling

const out = outputPath ?? engineConfig.kvCachePath;
if (!out) throw new Error('kv cache path required for persistence');
await engine.persistKvCache(out);

Prevention

When it happens

Trigger: Calling engine.persistKvCache('') or persistKvCache() on an engine built from a GgufEngineConfig that omits kvCachePath; config parsed from an env var that is unset, yielding undefined/empty string.

Common situations: Inline test configs omitting kvCachePath; empty-string defaults from config parsing; calling persist before the engine config was fully wired.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/5f8ec3d6591ed24b. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:362

            if (typeof chunk === 'string') yield chunk;
            else if (chunk?.text) yield chunk.text;
          }
          return;
        }
      } catch { /* fall through to single-chunk fallback */ }
    }
    const response = await this.generate(request);
    yield response.text;
  }

  /**
   * Persist the KV cache to an RVF-compatible binary file.
   * Format: RVKV magic | version u32 | model SHA-256 (32B) | entry count u32
   *         entries: [key_len u32, key, val_len u32, val] | footer SHA-256 (32B)
   */
  async persistKvCache(outputPath: string): Promise<void> {
    const path = outputPath || this.config.kvCachePath;
    if (!path) throw new Error('No KV cache output path specified');

    const modelHash = createHash('sha256').update(this.activeModelPath ?? 'no-model').digest();
    const entryBufs: Buffer[] = [];
    for (const [key, value] of this.kvCache) {
      const keyBuf = Buffer.from(key, 'utf-8');
      const hdr = Buffer.alloc(8);
      hdr.writeUInt32LE(keyBuf.length, 0);
      hdr.writeUInt32LE(value.length, 4);
      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);

View on GitHub (pinned to fa13ee4ad6)