ruvnet/ruflo · error

Invalid GGUF magic: 0x

Error message

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

What it means

parseGgufBuffer reads the first 4 bytes and requires the little-endian magic 0x46554747 (ASCII 'GGUF'); anything else throws immediately. The bytes at the given path are simply not a GGUF model — wrong file, a text/JSON document, an HTML error page saved with a .gguf extension, or a corrupted download.

Solutions

  1. Confirm the path: a real GGUF starts with the ASCII bytes 'GGUF' (hex 47 47 55 46)
  2. Re-download the model from a trusted source and verify size/checksum
  3. Fix the model path/config to point at the .gguf artifact, not a pointer or metadata file

Example fix

// before
const meta = await parseGgufHeader(cfg.modelPath);

// after
const fd = await open(cfg.modelPath);
const head = Buffer.alloc(4);
await fd.read(head, 0, 4, 0); await fd.close();
if (head.toString('ascii') !== 'GGUF') throw new Error('not a GGUF file');
const meta = await parseGgufHeader(cfg.modelPath);
Defensive patterns

Strategy: validation

Validate before calling

const fh = await open(path, 'r');
const head = Buffer.alloc(4);
await fh.read(head, 0, 4, 0); await fh.close();
if (head.toString('ascii') !== 'GGUF') throw new Error('not a GGUF model');
const meta = await parseGgufHeader(path);

Type guard

async function looksLikeGguf(path: string): Promise<boolean> {
  const fh = await open(path, 'r');
  const b = Buffer.alloc(4);
  const { bytesRead } = await fh.read(b, 0, 4, 0);
  await fh.close();
  return bytesRead === 4 && b.toString('ascii') === 'GGUF';
}

Try / catch

try { meta = await parseGgufHeader(path); }
catch (e) { if (e instanceof Error && e.message.includes('Invalid GGUF magic')) { rejectModel(path); } else throw e; }

Prevention

When it happens

Trigger: parseGgufHeader or model loading pointed at a non-GGUF path; a git-lfs pointer file or S3 error XML downloaded as the 'model'; passing a .safetensors/.bin file; a truncated-to-zero file.

Common situations: Config or CLI flag referencing the wrong path; download helpers that silently save error responses; case-mismatched filenames on case-sensitive filesystems.

Related errors


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

Appendix: 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 fa13ee4ad6)