tobi/qmd · error · Error
Model file is not valid GGUF (expected magic "GGUF", got "${
Error message
Model file is not valid GGUF (expected magic "GGUF", got "${inspection.magic ?? "unknown"}", file is ${formatModelFileSize(inspection.sizeBytes ?? 0)}).\nModel: ${modelUri}\nPath: ${filePath}\n\nThe file has been removed. Run the command again to re-download. What it means
validateGgufFile found the downloaded file does not start with the required 'GGUF' magic bytes, so it is not a usable model file. Unlike the HTML case, this catches truncated/corrupted downloads; the file has already been deleted and re-running the command will download it again.
Source
Thrown at src/llm.ts:476
try {
unlinkSync(filePath);
} catch { /* best effort */ }
if (inspection.kind === "html") {
throw new Error(
`Downloaded model file is an HTML page, not a GGUF model (${formatModelFileSize(inspection.sizeBytes ?? 0)}).\n` +
`Something is intercepting the download from huggingface.co (a proxy, firewall, or captive portal).\n\n` +
`Model: ${modelUri}\n` +
`Path: ${filePath}\n\n` +
`To fix this, either:\n` +
` 1. Try a HuggingFace mirror: HF_ENDPOINT=https://hf-mirror.com qmd embed\n` +
` 2. Download the model manually and set the env var, e.g.:\n` +
` QMD_EMBED_MODEL=/path/to/model.gguf qmd embed\n\n` +
`Note: 'qmd search' works without any model downloads.`
);
}
throw new Error(
`Model file is not valid GGUF (expected magic "GGUF", got "${inspection.magic ?? "unknown"}", file is ${formatModelFileSize(inspection.sizeBytes ?? 0)}).\n` +
`Model: ${modelUri}\n` +
`Path: ${filePath}\n\n` +
`The file has been removed. Run the command again to re-download.`
);
}
/**
* node-llama-cpp prints a multi-line download progress bar when the second
* argument is a directory string (`cli` defaults to true). Agent transcripts
* capture that as thousands of tokens. Always pass an options object so the
* bar is off unless the caller opts in (#776).
*/
function resolveModelFileArgs(cacheDir: string, cli = false): { directory: string; cli: boolean } {
return { directory: cacheDir, cli };
}
View on GitHub (pinned to dbfd0b4736)
Solutions
- Simply re-run the command — the bad file is removed and will re-download
- If it recurs, check disk space and network stability, or verify the mirror with HF_ENDPOINT
- Download the model manually from huggingface.co and set QMD_EMBED_MODEL=/path/to/model.gguf
- If using a manual path, confirm the file starts with the bytes 'GGUF' (e.g. head -c 4 file | xxd)
Defensive patterns
Strategy: retry
Validate before calling
function isGguf(filePath: string): boolean {
const fd = openSync(filePath, 'r');
const buf = Buffer.alloc(4);
readSync(fd, buf, 0, 4, 0); closeSync(fd);
return buf.toString('utf-8') === 'GGUF';
} Try / catch
for (let attempt = 1; attempt <= 3; attempt++) {
try { await pullModels(); break; }
catch (e) {
if (e instanceof Error && e.message.includes('not valid GGUF') && attempt < 3) continue;
throw e;
}
} Prevention
- Re-run after partial downloads — bad files are auto-removed
- Verify manual model files start with GGUF magic before setting QMD_EMBED_MODEL
- Ensure adequate disk space before large downloads
When it happens
Trigger: A model download interrupted mid-stream (disk full, process killed, connection dropped) leaving a partial file; a mirror or cache serving corrupted content; a manual QMD_EMBED_MODEL path pointing at a non-GGUF file.
Common situations: Killed qmd embed mid-download; flaky networks truncating large files; HF mirror serving bad artifacts; pointing QMD_EMBED_MODEL at a .bin or partially-downloaded file.
Related errors
AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28).
Data as JSON: /api/errors/1efe0ab89fa247c6.
Report an issue: GitHub.