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
- Confirm the path: a real GGUF starts with the ASCII bytes 'GGUF' (hex 47 47 55 46)
- Re-download the model from a trusted source and verify size/checksum
- 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
- Check the first 4 bytes before any GGUF parse
- Verify model downloads by size/checksum so error pages never reach the parser
- Give cache and model files distinct extensions to prevent path mix-ups
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
- Invalid KV cache magic: 0x
- String length exceeds remaining buffer
- Unknown GGUF array element type
- Unknown GGUF value type
- Unsupported GGUF version
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 windowView on GitHub (pinned to fa13ee4ad6)