janhq/jan · error
Invalid GGUF file(s)
Error message
Invalid GGUF file(s): ${error.message || 'File format validation failed'} What it means
During load, the extension validates the GGUF file(s) (including reading metadata such as nextn/draft layer counts). Any exception from that validation is logged and rethrown as 'Invalid GGUF file(s): ...', meaning the file is corrupt, truncated, or not a GGUF at all.
Solutions
- Delete the corrupt file and re-download the model; verify size/checksum against the source
- Confirm the file is actually GGUF format (magic bytes 'GGUF'), not safetensors or an HTML error page
- Re-import the model pointing at a known-good GGUF build
- Check available disk space and retry the download if it was truncated
Example fix
// before
await loadModel({ modelPath: '/models/model.gguf' }) // truncated download
// after
await downloadModel('https://.../model.gguf', { overwrite: true }) // re-fetch
await loadModel({ modelPath: '/models/model.gguf' }) Defensive patterns
Strategy: validation
Validate before calling
const fd = await fs.openAsync(path, 'r'); const buf = Buffer.alloc(4)
await fd.read(buf, 0, 4, 0)
if (buf.toString('ascii', 0, 4) !== 'GGUF') throw new Error(`not a GGUF: ${path}`)
await loadModel({ modelPath: path }) Try / catch
try {
await loadModel(opts)
} catch (e) {
if (e.message.startsWith('Invalid GGUF file(s):')) {
await redownloadCorruptedModel(opts.modelPath); return loadModel(opts)
}
throw e
} Prevention
- Verify download completeness (size/checksum) before loading
- Download GGUF, never safetensors, for this engine
- Beware proxies saving HTML error pages as .gguf
- Keep disk space headroom to avoid truncated writes
When it happens
Trigger: Calling loadModel with a modelPath pointing to a corrupt or truncated .gguf download, a non-GGUF file (e.g. safetensors, HTML error page saved as .gguf), or an mmproj file that fails format checks.
Common situations: Interrupted downloads leaving partial GGUFs; wrong file picked manually (safetensors from HuggingFace instead of GGUF); proxy/captive portal returning HTML that got saved as the model; corrupted storage.
Related errors
- Array length is unreasonably large
- Error reading metadata entry
- Failed to read key for metadata entry
- Failed to read name for tensor
- String length is unreasonably large
AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17).
Data as JSON: /api/errors/81d31802a03f1006.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/llamacpp-extension/src/index.ts:2092
// Only asked for a DFlash-architecture draft, since that is the one
// case a tensor decides (DSpark = DFlash + Markov head).
const hasMarkovHead =
draftMetadata.metadata?.['general.architecture'] === 'dflash'
? (await findGgufTensors(fullDraftPath, [MARKOV_HEAD_TENSOR]))
.length > 0
: undefined
specKind = resolveSpecDraftKind(draftMetadata.metadata, {
hasMarkovHead,
hint: opts.specDraftKind,
})
const draftLayers = detectMtpLayersFromGgufMeta(draftMetadata.metadata)
// Only an MTP head reports nextn layers; the other flavours have none,
// and the count is what makes the settings panel offer the toggle.
mtpLayers = draftLayers > 0 ? draftLayers : Math.max(mtpLayers, 1)
}
} catch (error) {
logger.error('GGUF validation failed:', error)
throw new Error(
`Invalid GGUF file(s): ${
error.message || 'File format validation failed'
}`
)
}
// Calculate file sizes
let size_bytes = (await fs.fileStat(fullModelPath)).size
if (mmprojPath) {
size_bytes += (
await fs.fileStat(await joinPath([janDataFolderPath, mmprojPath]))
).size
}
if (draftModelPath) {
size_bytes += (
await fs.fileStat(await joinPath([janDataFolderPath, draftModelPath]))
).size
}View on GitHub (pinned to 7205d770c1)