{"record":{"id":"ae855b907dbaf2cd","repo":"invoke-ai/InvokeAI","slug":"not-a-readable-gguf-file-e","errorCode":null,"errorMessage":"not a readable GGUF file: {e}","messagePattern":"not a readable GGUF file: (.+?)","errorType":"validation","errorClass":"NotAMatchError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/model_manager/configs/gemma2_encoder.py","lineNumber":100,"sourceCode":"        # Sanity check that tokenizer files live alongside the model (PiD calls\n        # AutoTokenizer.from_pretrained on the same directory).\n        if not any((mod.path / f).exists() for f in (\"tokenizer.json\", \"tokenizer.model\")):\n            raise NotAMatchError(\"directory does not contain Gemma2 tokenizer files (tokenizer.json/tokenizer.model)\")\n\n        return cls(**override_fields)\n\n\ndef _read_gguf_arch_and_hidden_size(path: Path) -> tuple[str, int | None]:\n    \"\"\"Read (general.architecture, <arch>.embedding_length) from a GGUF file's metadata.\n\n    Raises NotAMatchError if the file is not a readable GGUF or is missing the architecture marker.\n    \"\"\"\n    import gguf\n\n    try:\n        reader = gguf.GGUFReader(path)\n    except Exception as e:\n        raise NotAMatchError(f\"not a readable GGUF file: {e}\") from e\n\n    arch_field = reader.fields.get(\"general.architecture\")\n    if arch_field is None:\n        raise NotAMatchError(\"GGUF file is missing the 'general.architecture' metadata field\")\n    architecture = str(arch_field.contents())\n\n    hidden_field = reader.fields.get(f\"{architecture}.embedding_length\")\n    hidden_size = int(hidden_field.contents()) if hidden_field is not None else None\n    return architecture, hidden_size\n\n\nclass Gemma2Encoder_GGUF_Config(Config_Base):\n    \"\"\"Single-file GGUF-quantized Gemma-2-2b encoder for PiD (llama.cpp GGUF, e.g. gemma-2-2b-it-Q4_K_M.gguf).\n\n    Unlike the diffusers-directory config, this is a single ``.gguf`` file: the model config and the\n    tokenizer are read from the GGUF metadata, so no companion config.json / tokenizer files are required.\n    The weights are loaded natively by ``Gemma2EncoderGGUFLoader`` — the large 2D projections stay\n    quantized as ``GGMLTensor`` and are dequantized on demand by the model cache, rather than being fully","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/configs/gemma2_encoder.py#L82-L118","documentation":"NotAMatchError raised by _read_gguf_arch_and_hidden_size when gguf.GGUFReader(path) throws while opening the file, meaning the .gguf file cannot be parsed. The original reader exception text is embedded in the message. This is part of GGUF Gemma2 encoder identification, so any unreadable file is treated as 'not a match' and classification moves on to other config classes.","triggerScenarios":"from_model_on_disk on a file with a .gguf suffix whose contents are not valid GGUF: truncated/partial download, HTML error page saved as .gguf, corrupted or LFS-pointer file, or a file with a .gguf extension that is actually a different format.","commonSituations":"Interrupted downloads from HuggingFace (partial size); git-lfs pointer files checked out without 'git lfs pull'; CDN error pages saved instead of the model; renamed non-GGUF binaries.","solutions":["Re-download the .gguf file and verify its size/checksum against the HuggingFace repo","If the repo uses git-lfs, run 'git lfs pull' so the real binary replaces the pointer file","Confirm the file starts with the GGUF magic bytes (e.g. head -c 4 file.gguf shows 'GGUF')","Check the embedded exception text in the message for the underlying cause (permission denied vs parse error)"],"exampleFix":"// before\nwget -c https://huggingface.co/.../gemma-2-2b-it-Q4_K_M.gguf  # interrupted, truncated\n// after\nhuggingface-cli download <repo> gemma-2-2b-it-Q4_K_M.gguf  # verifies size/hash","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef looks_like_gguf(path: str | Path) -> bool:\n    p = Path(path)\n    if p.suffix.lower() != \".gguf\" or not p.is_file():\n        return False\n    try:\n        with open(p, \"rb\") as f:\n            return f.read(4) == b\"GGUF\"\n    except OSError:\n        return False","typeGuard":"def is_plausible_gguf_download(p: Path, expected_min_bytes: int) -> bool:\n    return looks_like_gguf(p) and p.stat().st_size >= expected_min_bytes","tryCatchPattern":"try:\n    import_model(gguf_path)\nexcept NotAMatchError as e:\n    if \"not a readable GGUF\" in str(e):\n        print(\"File is truncated/corrupt — re-download and verify size or sha256\")","preventionTips":["Use huggingface-cli download (or verify sha256) instead of raw wget/curl so truncation is caught","For git-lfs repos, run git lfs pull — never commit the pointer file as the model","Check the first 4 bytes are 'GGUF' after any manual download"],"tags":["gguf","corrupt-file","model-import"],"backgroundTag":"corrupt-model-file","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}