ruvnet/ruflo · error · Error

Invalid GGUF magic: 0x${magic.toString(16)} (expected 0x${GG

Error message

Invalid GGUF magic: 0x${magic.toString(16)} (expected 0x${GGUF_MAGIC.toString(16)})

What it means

Thrown by parseGgufBuffer when the first u32 of the file is not GGUF_MAGIC. The magic number is the format's identity check; a mismatch means the file is not GGUF (or is a different endianness / a different format that happens to be passed in). This is the earliest possible parse failure and runs before version/tensor/KV reads.

Source

Thrown at v3/@claude-flow/cli/src/appliance/gguf-engine.ts:170

export async function parseGgufHeader(path: string): Promise<GgufMetadata> {
  const fileInfo = await fsStat(path);
  const readSize = Math.min(fileInfo.size, 256 * 1024);
  const fh = await open(path, 'r');
  try {
    const buf = Buffer.alloc(readSize);
    await fh.read(buf, 0, readSize, 0);
    return parseGgufBuffer(buf, fileInfo.size, path);
  } finally {
    await fh.close();
  }
}

function parseGgufBuffer(buf: Buffer, fileSize: number, filePath: string): GgufMetadata {
  const reader = new BufferReader(buf);

  const magic = reader.readU32();
  if (magic !== GGUF_MAGIC) {
    throw new Error(`Invalid GGUF magic: 0x${magic.toString(16)} (expected 0x${GGUF_MAGIC.toString(16)})`);
  }

  const version = reader.readU32();
  if (version < 2 || version > 3) {
    throw new Error(`Unsupported GGUF version: ${version} (expected 2 or 3)`);
  }

  const tensorCount = reader.readU64AsNumber();
  const kvCount = reader.readU64AsNumber();

  const metadata: Record<string, unknown> = {};
  for (let i = 0; i < kvCount; i++) {
    if (reader.remaining < 12) break;
    try {
      const key = reader.readString();
      metadata[key] = readGgufValue(reader);
    } catch {
      break; // reached end of read window

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Confirm the path points to an actual GGUF file (check the file command / first bytes; GGUF magic is 'GGUF' = 0x46554747).
  2. Re-download from the source if the file looks like an HTML error page or is suspiciously small.
  3. Gate parseGgufHeader with a quick magic-byte check so you can give a clearer error or skip non-GGUF files in a directory scan.
  4. Verify the file was not truncated to zero bytes by a failed transfer.

Example fix

// before
const meta = await parseGgufHeader(candidatePath);

// after
async function isGguf(path: string): Promise<boolean> {
  const fh = await open(path, 'r');
  const head = Buffer.alloc(4);
  await fh.read(head, 0, 4, 0);
  await fh.close();
  return head.readUInt32LE(0) === 0x46554747;
}
if (!(await isGguf(candidatePath))) throw new Error('not a GGUF file; refusing to parse');
Defensive patterns

Strategy: validation

Validate before calling

import { open } from 'node:fs/promises';
async function isGgufFile(path: string): Promise<boolean> {
  const fh = await open(path, 'r');
  const head = Buffer.alloc(4);
  await fh.read(head, 0, 4, 0);
  await fh.close();
  return head.readUInt32LE(0) === 0x46554747; // 'GGUF'
}
if (!(await isGgufFile(path))) throw new Error('not a GGUF file');

Type guard

function isGgufMagic(buf: Buffer): boolean {
  return buf.length >= 4 && buf.readUInt32LE(0) === 0x46554747;
}

Try / catch

try {
  return await parseGgufHeader(path);
} catch (e) {
  if (e instanceof Error && /Invalid GGUF magic/.test(e.message)) {
    throw new Error(`'${path}' is not a GGUF file`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling parseGgufHeader (or otherwise parsing) on a file that is not GGUF: a safetensors/GGML/bin file, a text file, or a renamed download. Also fires if the file is empty or only a few bytes long so the u32 read yields zeros.

Common situations: Wrong file selected in a model picker (e.g. a tokenizer or config JSON named .gguf), a download that produced an HTML error page saved with the .gguf extension, or endianness confusion. The message helpfully prints both the found and expected magic in hex.

Related errors


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