ruvnet/ruflo · error · Error

Invalid RVFA magic: expected "RVFA", got "${magic}"

Error message

Invalid RVFA magic: expected "RVFA", got "${magic}"

What it means

Thrown by RvfaReader.fromBuffer() when the first 4 bytes are not ASCII 'RVFA'. The buffer passed the preamble-size check but its identity bytes do not match the appliance format. This distinguishes a genuinely malformed file from a format mismatch (e.g. an RVFP patch or unrelated binary).

Source

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

export class RvfaReader {
  private buf: Buffer;
  private header: RvfaHeader;

  private constructor(buf: Buffer, header: RvfaHeader) {
    this.buf = buf;
    this.header = header;
  }

  /** Parse an RVFA image from an in-memory Buffer. */
  static fromBuffer(buf: Buffer): RvfaReader {
    if (buf.length < PREAMBLE_SIZE) {
      throw new Error('Buffer too small to contain RVFA preamble');
    }

    // Magic
    const magic = buf.subarray(0, MAGIC_SIZE).toString('ascii');
    if (magic !== 'RVFA') {
      throw new Error(`Invalid RVFA magic: expected "RVFA", got "${magic}"`);
    }

    // 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) {

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Confirm the input is an RVFA appliance produced by RvfaWriter.build().
  2. If the file is an RVFP patch, use RvfaPatcher.parsePatchHeader instead.
  3. Validate magic bytes (buf.subarray(0,4).toString('ascii') === 'RVFA') before parsing.
  4. Re-acquire the appliance from a known-good source if the file is wrong.

Example fix

// before
const reader = await RvfaReader.fromFile(path);

// after
const head = await fs.open(path, 'r').then(h => { const b = Buffer.alloc(4); h.read(b,0,0,4); h.close(); return b; });
if (head.toString('ascii') !== 'RVFA') throw new Error('Not an RVFA appliance');
const reader = await RvfaReader.fromFile(path);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

function isRvfaBuffer(buf: unknown): buf is Buffer {
  return Buffer.isBuffer(buf) && buf.length >= 4 && buf.subarray(0, 4).toString('ascii') === 'RVFA';
}

Try / catch

try {
  const reader = RvfaReader.fromBuffer(buf);
} catch (e) {
  if (/Invalid RVFA magic/.test((e as Error).message)) {
    throw new Error('Input is not an RVFA appliance; if this is a .rvfp patch, use RvfaPatcher instead');
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an RVFP patch buffer, a gzip stream, a text file, or random bytes to fromBuffer/fromFile. The first 4 bytes are anything other than 0x52 0x56 0x46 0x41.

Common situations: Pointing fromFile() at a .rvfp patch instead of a .rvfa appliance; reading a file that was overwritten; feeding a decompressed stream that lost its magic; cross-format confusion in a deploy pipeline.

Related errors


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