Zackriya-Solutions/meetily · error

Invalid model file: magic number {:?} doesn't match GGUF/GGM

Error message

Invalid model file: magic number {:?} doesn't match GGUF/GGML

What it means

validate_model_file reads the first 4 bytes and requires the magic 'GGUF' (or a legacy 'ggjt'/'ggla'/'ggml'). Any other bytes produce this error: the file at the model path is not a GGUF model - most commonly an HTML error page that was saved in place of the binary.

Source

Thrown at frontend/src-tauri/src/summary/summary_engine/model_manager.rs:788

    }

    /// Validate that a file is a valid GGUF model
    async fn validate_gguf_file(&self, path: &PathBuf) -> Result<()> {
        let mut file = fs::File::open(path).await?;

        // Read first 4 bytes to check for GGUF magic number
        use tokio::io::AsyncReadExt;
        let mut magic = [0u8; 4];
        file.read_exact(&mut magic).await?;

        // GGUF magic number is "GGUF" (0x47475546)
        if &magic == b"GGUF" {
            Ok(())
        } else if &magic == b"ggjt" || &magic == b"ggla" || &magic == b"ggml" {
            // Older formats (GGML, GGJT)
            Ok(())
        } else {
            Err(anyhow!(
                "Invalid model file: magic number {:?} doesn't match GGUF/GGML",
                magic
            ))
        }
    }

    /// Cancel an ongoing download
    pub async fn cancel_download(&self, model_name: &str) -> Result<()> {
        log::info!("Cancelling download for model: {}", model_name);

        // Set cancellation flag - download loop will detect this and handle cleanup
        {
            let mut cancel_flag = self.cancel_download_flag.write().await;
            *cancel_flag = Some(model_name.to_string());
        }

        // Note: active_downloads cleanup is handled by the download loop when it detects
        // the cancellation flag. This avoids double-removal race condition.

View on GitHub (pinned to 0281737d87)

Solutions

  1. Delete the bad file via delete_model and re-download
  2. Check the URL actually returns the binary: curl -sL <url> | head -c 4 should print GGUF
  3. If installing manually, verify with xxd -l 4 <file> that it shows 47475546 ('GGUF') and name it exactly as model_def.gguf_file
  4. Clear proxy/CDN/auth interference (captive portals, authenticated mirrors) and retry
Defensive patterns

Strategy: validation

Validate before calling

// Cheap magic check before trusting any model file
fn is_gguf_file(path: &Path) -> bool {
    use std::io::Read;
    let mut f = match std::fs::File::open(path) { Ok(f) => f, Err(_) => return false };
    let mut magic = [0u8; 4];
    f.read_exact(&mut magic).is_ok() && (&magic == b"GGUF" || &magic == b"ggml" || &magic == b"ggjt" || &magic == b"ggla")
}

Type guard

fn is_valid_model_file(path: &Path) -> bool {
    std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(false) && is_gguf_file(path)
}

Try / catch

try { manager.download_model(name).await? }
catch (e) if e.to_string().contains("magic number") {
    // an HTML error page or wrong file was saved - delete and re-download from the canonical URL
    manager.delete_model(name).await.ok();
    manager.download_model(name).await?;
}

Prevention

When it happens

Trigger: Post-download validation or load reads a file whose header is not GGUF/GGML: a 404/redirect/auth-wall HTML page saved as the .gguf, a corrupted first block from a bad resume, or a user manually placing a non-GGUF file in the models/summary directory.

Common situations: HuggingFace/LFS redirect or CDN error page saved instead of the binary, captive portal intercepting the download, renaming a .bin or .onnx file to .gguf, partial-file resume where offsets shifted.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16). Data as JSON: /api/errors/a14a21f8602aa305. Report an issue: GitHub.