ruvnet/ruflo · error

Buffer too small for RVFP preamble

Error message

Buffer too small for RVFP preamble

What it means

RvfaPatcher.parsePatchHeader needs at least the 12-byte preamble (PRE = 4 magic + 4 version + 4 header-length) before it can read anything. This fires when the input is shorter than 12 bytes — an empty or near-empty buffer handed to the parser, typically a failed download saved anyway or a wrong file.

Solutions

  1. Check buf.length >= 12 before parsing (magic + version + headerLen alone occupy 12 bytes)
  2. Verify the source: stat the downloaded .rvfp and compare with the expected size, or re-fetch it
  3. Confirm you are passing the complete patch file, not a subarray slice of it

Example fix

// before
const header = RvfaPatcher.parsePatchHeader(await readFile(p)); // p empty after a failed fetch

// after
const buf = await readFile(p);
if (buf.length < 12) throw new Error(`Patch too small (${buf.length}B) — re-fetch ${p}`);
const header = RvfaPatcher.parsePatchHeader(buf);
Defensive patterns

Strategy: validation

Validate before calling

const buf = await readFile(patchPath);
if (buf.length < 12) { // RVFP preamble: 4 magic + 4 version + 4 header_len
  throw new Error(`Not an RVFP patch (${buf.length} bytes) — re-download`);
}

Type guard

function looksLikeRvfpPatch(buf: Buffer): boolean {
  return buf.length >= 12 && buf.subarray(0, 4).toString('ascii') === 'RVFP';
}

Prevention

When it happens

Trigger: `RvfaPatcher.parsePatchHeader(buf)` or `verifyPatch(buf)` with an empty Buffer (0 bytes), a 1–11 byte stub from an aborted fetch, or a wrongly sliced subarray that trimmed the whole patch away.

Common situations: A gateway returned an empty body that was written to disk; reading a path that does not exist and defaulting to an empty buffer; tests feeding truncated fixtures; passing a payload slice instead of the whole patch file.

Related errors


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

Appendix: source

Thrown at v3/@claude-flow/cli/src/appliance/rvfa-distribution.ts:191

      targetApplianceName: opts.targetName, targetApplianceVersion: opts.targetVersion,
      targetSection: opts.sectionId, patchVersion: opts.patchVersion,
      created: new Date().toISOString(), newSectionSize: payload.length,
      newSectionSha256: sha256(payload), compression: comp,
    };
    if (opts.privateKey && opts.signedBy) {
      const signable = Buffer.concat([Buffer.from(canonicalJson(header), 'utf-8'), payload]);
      header.signature = edSign(signable, opts.privateKey);
      header.signedBy = opts.signedBy;
    }
    const hJson = Buffer.from(JSON.stringify(header), 'utf-8');
    const magic = Buffer.from('RVFP');
    const ver = Buffer.alloc(4); ver.writeUInt32LE(RVFP_VERSION, 0);
    const hLen = Buffer.alloc(4); hLen.writeUInt32LE(hJson.length, 0);
    return Buffer.concat([magic, ver, hLen, hJson, payload, sha256B(payload)]);
  }

  static parsePatchHeader(buf: Buffer): RvfpHeader {
    if (buf.length < PRE) throw new Error('Buffer too small for RVFP preamble');
    const magic = buf.subarray(0, 4).toString('ascii');
    if (magic !== 'RVFP') throw new Error(`Invalid RVFP magic: "${magic}"`);
    const ver = buf.readUInt32LE(4);
    if (ver !== RVFP_VERSION) throw new Error(`Unsupported RVFP version: ${ver}`);
    const hLen = buf.readUInt32LE(8);
    if (PRE + hLen > buf.length) throw new Error('Buffer too small for declared header');
    const h = JSON.parse(buf.subarray(PRE, PRE + hLen).toString('utf-8')) as RvfpHeader;
    if (h.magic !== 'RVFP') throw new Error('RVFP header magic mismatch');
    return h;
  }

  static async verifyPatch(buf: Buffer): Promise<PatchVerifyResult> {
    const errors: string[] = [];
    let header: RvfpHeader;
    try { header = RvfaPatcher.parsePatchHeader(buf); } catch (e) {
      const empty: RvfpHeader = {
        magic: 'RVFP', version: 0, targetApplianceName: '', targetApplianceVersion: '',
        targetSection: '', patchVersion: '', created: '', newSectionSize: 0,

View on GitHub (pinned to fa13ee4ad6)