ruvnet/ruflo · error · Error

Footer hash must be ${SHA256_SIZE} bytes, got ${footerHash.l

Error message

Footer hash must be ${SHA256_SIZE} bytes, got ${footerHash.length}

What it means

Thrown by signSections when footerHash is not exactly 32 bytes (SHA256_SIZE). The signer signs a fixed-size digest, so a wrong-size input is a caller programmer error, not a data problem.

Source

Thrown at v3/@claude-flow/cli/src/appliance/rvfa-signing.ts:327

    };

    // Embed signature in header and rebuild
    header.signature = metadata;
    const rebuilt = rebuildRvfa(buf, header, sectionData, footer);
    await writeFile(rvfaPath, rebuilt);

    return metadata;
  }

  /**
   * Sign a section footer hash (detached signature).
   *
   * @param footerHash  The 32-byte SHA256 footer hash from an RVFA file.
   * @returns Hex-encoded Ed25519 signature.
   */
  async signSections(footerHash: Buffer): Promise<string> {
    if (footerHash.length !== SHA256_SIZE) {
      throw new Error(
        `Footer hash must be ${SHA256_SIZE} bytes, got ${footerHash.length}`,
      );
    }
    const sig = sign(null, footerHash, this.keyObj);
    return sig.toString('hex');
  }

  /**
   * Sign an RVFP patch file (detached signature).
   *
   * @param patchData  The raw patch binary data.
   * @returns Hex-encoded Ed25519 signature.
   */
  async signPatch(patchData: Buffer): Promise<string> {
    const digest = createHash('sha256').update(patchData).digest();
    const sig = sign(null, digest, this.keyObj);
    return sig.toString('hex');
  }

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Pass the 32-byte footer hash from parseRvfaBinary, or compute crypto.createHash('sha256').update(data).digest().
  2. If you hold a hex string, decode it first: Buffer.from(hex, 'hex').
  3. Confirm the digest algorithm is SHA256 (32 bytes), not SHA512 or SHA1.

Example fix

// before
const sig = await signer.signSections(Buffer.from(footerHex));

// after
const sig = await signer.signSections(Buffer.from(footerHex, 'hex'));
Defensive patterns

Strategy: validation

Validate before calling

if (!Buffer.isBuffer(footerHash) || footerHash.length !== 32) {
  throw new Error('footerHash must be a 32-byte SHA256 Buffer');
}
const sig = await signer.signSections(footerHash);

Type guard

function isSha256Digest(b: unknown): b is Buffer {
  return Buffer.isBuffer(b) && b.length === 32;
}

Prevention

When it happens

Trigger: Calling signer.signSections(buf) where buf is a hex string mistaken for bytes, a 64-byte SHA512 digest, the raw footer bytes, or section data instead of the digest.

Common situations: Passing a hex-encoded string (64 ASCII bytes) instead of decoding it; passing a SHA512 digest; passing the section payload rather than its hash.

Related errors


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