ruvnet/ruflo · error
Invalid RVFA magic: expected "RVFA", got
Error message
Invalid RVFA magic: expected "RVFA", got "${magic}" What it means
parseRvfaBinary found that the first 4 bytes are not the ASCII string 'RVFA'. The magic number is the format's first-line identity check — a wrong magic means the bytes are a different format entirely (or shifted by a prefix). The message helpfully echoes the bytes it saw, which is your main diagnostic.
Solutions
- Read the echoed magic in the message and identify the actual format ('PK' = zip, '\u001f\u008b' = gzip, 'ustar' = tar) then unwrap/point at the real RVFA file
- If the image is gzip-wrapped, gunzip it first — RVFA sections use internal gzip but the outer file must start with the magic
- Check the path/config feeding the signing step — it's usually pointed at the wrong artifact
- Regenerate the artifact with RvfaWriter if the original was never RVFA to begin with
Example fix
// before — verifying a still-compressed download
const buf = await readFile('appliance.rvfa.gz');
await verifier.verifyFile(buf, pub);
// after — decompress the transport layer first
const buf = gunzipSync(await readFile('appliance.rvfa.gz'));
await verifier.verifyFile(buf, pub); Defensive patterns
Strategy: validation
Validate before calling
function looksLikeRvfa(buf: Buffer): boolean {
return buf.length >= 4 && buf.subarray(0, 4).toString('ascii') === 'RVFA';
}
// for gzipped transports: gunzipSync(buf) first, then check Type guard
function isRvfaBuffer(buf: Buffer): buf is Buffer {
return buf.subarray(0, 4).toString('ascii') === 'RVFA';
} Try / catch
try { await verifyFile(buf, pub); }
catch (e) {
if (/Invalid RVFA magic/.test(String((e as Error).message))) {
// message echoes the bytes: 'PK'=zip, 0x1f8b=gzip -> unwrap and retry with the real payload
}
throw e;
} Prevention
- Pin artifact paths explicitly in CI; never glob for '*.rvfa' next to other artifacts
- Unwrap transport compression (gzip) before verification — magic must sit at offset 0
- Use the echoed magic from the message to identify what you actually loaded
When it happens
Trigger: Feeding a non-RVFA file to the signing APIs: a tarball/zip/gzip artifact renamed to .rvfa, a Docker/OCI layer blob, or an RVFA image wrapped in an extra envelope so the magic sits past offset 0. The echoed magic in the message (e.g. 'PK\u0003\u0004' for zip, '\u001f\u008b' gzip) identifies the real format.
Common situations: Artifact-type confusion in CI (verify step pointed at the wrong artifact); images double-compressed (gzip'd RVFA); concatenation wrappers or signature-prepended formats shifting the payload; typos in file paths picking up a sibling file of another type.
Related errors
- Buffer too small to be a valid RVFA file
- Failed to parse RVFA header JSON
- Footer hash must be bytes, got
- Header length extends beyond buffer
- Invalid GGUF magic: 0x
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/c8a03f032945d50d.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/rvfa-signing.ts:175
/**
* Parse an RVFA binary into its components without full validation.
* Returns the header object, header JSON bytes, section data region, and footer.
*/
function parseRvfaBinary(buf: Buffer): {
header: Record<string, unknown>;
headerStart: number;
headerEnd: number;
sectionData: Buffer;
footer: Buffer;
} {
if (buf.length < PREAMBLE_SIZE + SHA256_SIZE) {
throw new Error('Buffer too small to be a valid RVFA file');
}
const magic = buf.subarray(0, 4).toString('ascii');
if (magic !== 'RVFA') {
throw new Error(`Invalid RVFA magic: expected "RVFA", got "${magic}"`);
}
const headerLen = buf.readUInt32LE(8);
const headerStart = PREAMBLE_SIZE;
const headerEnd = headerStart + headerLen;
if (headerEnd > buf.length - SHA256_SIZE) {
throw new Error('Header length extends beyond buffer');
}
const headerJson = buf.subarray(headerStart, headerEnd).toString('utf-8');
let header: Record<string, unknown>;
try {
header = JSON.parse(headerJson) as Record<string, unknown>;
} catch {
throw new Error('Failed to parse RVFA header JSON');
}
View on GitHub (pinned to fa13ee4ad6)