ruvnet/ruflo · error

Failed to parse RVFA header JSON

Error message

Failed to parse RVFA header JSON

What it means

Thrown when the byte range [12, 12+headerLen) of the RVFA buffer exists (the length check at rvfa-format.ts:337 passed) but does not parse as JSON. The bytes are present yet their content is not valid UTF-8 JSON — either the header region is corrupted, or headerLen is subtly wrong so the slice starts mid-JSON or bleeds into binary section data.

Solutions

  1. Dump the slice and inspect it: buf.subarray(12, 12 + buf.readUInt32LE(8)).toString('utf8') — partial JSON means headerLen is wrong; binary garbage means offsets shifted
  2. Regenerate the appliance image with a current RvfaWriter — the header also carries section offsets, so patching it by hand is fragile
  3. If you control the writer, ensure it serializes with Buffer.from(JSON.stringify(header), 'utf8') (no BOM) and stores that exact byte length
  4. Compare the writer and reader package versions; a layout change across versions produces exactly this off-by-N slicing

Example fix

// before — opaque parse failure inside fromBuffer
const reader = RvfaReader.fromBuffer(buf);

// after — surface exactly what's in the header region first
const headerLen = buf.readUInt32LE(8);
const slice = buf.subarray(12, 12 + headerLen).toString('utf8');
JSON.parse(slice); // throws with position info pointing at the bad bytes
Defensive patterns

Strategy: try-catch

Validate before calling

const headerLen = buf.readUInt32LE(8);
const slice = buf.subarray(12, 12 + headerLen).toString('utf8');
try { JSON.parse(slice); } catch {
  console.error('header not JSON, first bytes:', slice.slice(0, 80));
  throw new Error('refusing to parse: header region corrupt');
}

Try / catch

try {
  reader = RvfaReader.fromBuffer(buf);
} catch (e) {
  if (e instanceof Error && e.message === 'Failed to parse RVFA header JSON') {
    // dump subarray(12, 12+readUInt32LE(8)) to find where JSON breaks
  }
  throw e;
}

Prevention

When it happens

Trigger: RvfaReader.fromBuffer/fromFile on a file where bytes 12..12+headerLen are not valid JSON: headerLen off by a few bytes so the slice cuts the JSON short or includes section bytes; the header was written as UTF-16 or with a BOM; the file was byte-edited or re-encoded after generation.

Common situations: A writer/reader version mismatch that shifts the preamble layout; text editors or transfer pipelines that 'helpfully' re-encode the file; custom scripts rewriting the preamble with wrong offsets; archive corruption that happens to keep total size plausible.

Understand the failure class

Related errors


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

Appendix: source

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

    // 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;
    for (const sec of header.sections) {
      if (sec.offset < 0 || sec.size < 0) {
        throw new Error(`Section "${sec.id}" has negative offset or size`);
      }
      if (sec.offset + sec.size > totalSize - SHA256_SIZE) {
        throw new Error(
          `Section "${sec.id}" extends beyond buffer ` +
            `(offset=${sec.offset}, size=${sec.size}, bufLen=${totalSize})`,
        );

View on GitHub (pinned to fa13ee4ad6)