ruvnet/ruflo · error

Buffer too small to contain declared header

Error message

Buffer too small to contain declared header

What it means

Thrown by RvfaReader.fromBuffer when the u32LE header length stored at byte offset 8 (after the 4-byte 'RVFA' magic and 4-byte version) plus the 12-byte preamble exceeds the actual buffer length. The RVFA format declares its JSON header size up front; if the file is truncated or the length field is corrupt, the declared header cannot physically fit and the reader aborts before attempting to parse JSON. This is a hard integrity check — the reader never clamps or guesses.

Solutions

  1. Verify the file size against the source and re-download/rebuild — truncation is the most common cause; confirm the 32-byte SHA256 footer is actually present at the end
  2. Inspect the preamble: buf.readUInt32LE(8) must be <= buf.length - 12 - 32; if it is enormous, the length field itself is corrupt and the file is unrecoverable
  3. If you generate RVFA buffers yourself, write headerLen as the exact byte length of the serialized JSON header (see exampleFix)
  4. Check transfer integrity with checksums (rsync -c, sha256sum on both ends) before retrying

Example fix

// before — declared length doesn't match the JSON actually written
const headerJson = Buffer.from(JSON.stringify(header));
preamble.writeUInt32LE(headerJson.length + 64, 8); // padded guess -> truncation read-back

// after — declare the exact JSON byte length
const headerJson = Buffer.from(JSON.stringify(header));
preamble.writeUInt32LE(headerJson.length, 8);
const image = Buffer.concat([preamble, headerJson, sectionData, footer]);
Defensive patterns

Strategy: validation

Validate before calling

import { RVFA_MAGIC, RVFA_VERSION } from './rvfa-format.js';

function canContainHeader(buf: Buffer): boolean {
  if (buf.length < 44) return false;
  if (!buf.subarray(0, 4).equals(RVFA_MAGIC)) return false;
  if (buf.readUInt32LE(4) !== RVFA_VERSION) return false;
  const headerLen = buf.readUInt32LE(8);
  return headerLen <= 1024 * 1024 && 12 + headerLen <= buf.length - 32;
}

Type guard

function isPlausibleRvfa(buf: Buffer): buf is Buffer {
  return buf.length >= 44 && 12 + buf.readUInt32LE(8) <= buf.length - 32;
}

Try / catch

try {
  const reader = RvfaReader.fromBuffer(buf);
} catch (e) {
  if (e instanceof Error && e.message === 'Buffer too small to contain declared header') {
    // file truncated: re-download, don't retry with the same bytes
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling RvfaReader.fromBuffer(buf) or await RvfaReader.fromFile(path) where readUInt32LE(8) + 12 > buf.length. Concretely: a partially downloaded .rvfa image, a file cut short by a disk-full write, or a hand-assembled buffer whose headerLen field doesn't match the JSON bytes actually appended.

Common situations: Interrupted scp/cp or CI artifact size limits truncating the image; disk-full during appliance build; test fixtures that write the preamble but forget to append the header JSON; a length field written in the wrong endianness or at the wrong offset by custom tooling.

Related errors


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

Appendix: source

Thrown at v3/@claude-flow/cli/src/appliance/rvfa-format.ts:337

    }

    // Version
    const version = buf.readUInt32LE(MAGIC_SIZE);
    if (version !== RVFA_VERSION) {
      throw new Error(
        `Unsupported RVFA version: ${version} (expected ${RVFA_VERSION})`,
      );
    }

    // Header length
    const headerLen = buf.readUInt32LE(MAGIC_SIZE + VERSION_SIZE);
    if (headerLen > MAX_HEADER_JSON_SIZE) {
      throw new Error(
        `Header JSON exceeds maximum size (${headerLen} > ${MAX_HEADER_JSON_SIZE})`,
      );
    }
    if (PREAMBLE_SIZE + headerLen > buf.length) {
      throw new Error('Buffer too small to contain declared header');
    }

    // Parse header JSON
    const headerSlice = buf.subarray(PREAMBLE_SIZE, PREAMBLE_SIZE + headerLen);
    let parsed: unknown;
    try {
      parsed = JSON.parse(headerSlice.toString('utf-8'));
    } catch {
      throw new Error('Failed to parse RVFA header JSON');
    }

    if (!validateHeader(parsed)) {
      throw new Error('RVFA header failed validation');
    }
    const header = parsed as RvfaHeader;

    // Bounds-check every section offset
    const totalSize = buf.length;

View on GitHub (pinned to fa13ee4ad6)