{"record":{"id":"11cb5508ddf8d5e3","repo":"chroma-core/chroma","slug":"downloaded-file-fname-does-not-match-expected-sh","errorCode":null,"errorMessage":"Downloaded file {fname} does not match expected SHA256 hash. Corrupted download or malicious file.","messagePattern":"Downloaded file (.+?) does not match expected SHA256 hash\\. Corrupted download or malicious file\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"chromadb/utils/embedding_functions/onnx_mini_lm_l6_v2.py","lineNumber":122,"sourceCode":"            fname: The path to save the model to.\n            chunk_size: The chunk size to use when downloading.\n        \"\"\"\n        with httpx.stream(\"GET\", url) as resp:\n            total = int(resp.headers.get(\"content-length\", 0))\n            with open(fname, \"wb\") as file, self.tqdm(\n                desc=str(fname),\n                total=total,\n                unit=\"iB\",\n                unit_scale=True,\n                unit_divisor=1024,\n            ) as bar:\n                for data in resp.iter_bytes(chunk_size=chunk_size):\n                    size = file.write(data)\n                    bar.update(size)\n\n        if not _verify_sha256(fname, self._MODEL_SHA256):\n            os.remove(fname)\n            raise ValueError(\n                f\"Downloaded file {fname} does not match expected SHA256 hash. Corrupted download or malicious file.\"\n            )\n\n    # Use pytorches default epsilon for division by zero\n    # https://pytorch.org/docs/stable/generated/torch.nn.functional.normalize.html\n    def _normalize(self, v: npt.NDArray[np.float32]) -> npt.NDArray[np.float32]:\n        \"\"\"\n        Normalize a vector.\n\n        Args:\n            v: The vector to normalize.\n\n        Returns:\n            The normalized vector.\n        \"\"\"\n        norm = np.linalg.norm(v, axis=1)\n        # Handle division by zero\n        norm[norm == 0] = 1e-12","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/utils/embedding_functions/onnx_mini_lm_l6_v2.py#L104-L140","documentation":"ONNXMiniLM_L6_V2 downloads the all-MiniLM-L6-v2 ONNX model into ~/.cache/chroma/onnx_models/all-MiniLM-L6-v2/ and verifies its SHA256 against the pinned constant 913d7300...a16ec3. On mismatch the file is deleted (os.remove) and ValueError is raised; the @retry decorator on _download re-attempts up to 3 times with 1-3s random waits specifically when the message contains \"does not match expected SHA256\", so this error surfaces only after repeated corrupted downloads. It guards both truncated downloads and supply-chain tampering.","triggerScenarios":"Flaky network/proxy that truncates the ~80MB download (mismatch survives 3 retries); a MITM proxy or antivirus rewriting the file; a partially-written cache file from a previously killed process (note the code removes the bad file before raising, so a stale corrupt file alone is cleaned up); a compromised or hijacked download host serving a different binary.","commonSituations":"Corporate proxies with aggressive content inspection; hotel/public wifi drops mid-download; full or flaky disk in ~/.cache; CI runners with unreliable egress; the security-sensitive case where the hash genuinely doesn't match (treat as incident).","solutions":["Check network stability and retry after the bad file has been auto-removed; if a stale corrupt file lingers, clear the cache: rm -rf ~/.cache/chroma/onnx_models/all-MiniLM-L6-v2","If behind a proxy, bypass or fix it (configure HTTP(S)_PROXY properly, disable TLS interception for the download host) so the binary arrives intact","Pre-download the model manually on a trusted machine, verify its SHA256 equals 913d7300ceae3b2dbc2c50d1de4baacab4be7b9380491c27fab7418616a16ec3, and place it at ~/.cache/chroma/onnx_models/all-MiniLM-L6-v2/onnx.tar.gz (the DOWNLOAD_PATH) on the target machine","If the hash mismatch persists on a known-good network, treat it as a potential tampering signal: do not disable verification, investigate the source"],"exampleFix":"// shell — clear a corrupted cache and retry on a stable network\nrm -rf ~/.cache/chroma/onnx_models/all-MiniLM-L6-v2\npython -c \"from chromadb.utils.embedding_functions.onnx_mini_lm_l6_v2 import ONNXMiniLM_L6_V2; ONNXMiniLM_L6_V2()\"","handlingStrategy":"retry","validationCode":"import hashlib\nfrom pathlib import Path\nEXPECTED = \"913d7300ceae3b2dbc2c50d1de4baacab4be7b9380491c27fab7418616a16ec3\"\nmodel_dir = Path.home() / \".cache\" / \"chroma\" / \"onnx_models\" / \"all-MiniLM-L6-v2\"\nfor f in model_dir.glob(\"*\") if model_dir.exists() else []:\n    h = hashlib.sha256(f.read_bytes()).hexdigest()\n    if f.name.endswith(\".tar.gz\") and h != EXPECTED:\n        f.unlink()  # remove corrupt cache so Chroma re-downloads\n# construction now downloads fresh if needed","typeGuard":null,"tryCatchPattern":"from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential\n@retry(reraise=True, stop=stop_after_attempt(3),\n       retry=retry_if_exception(lambda e: isinstance(e, ValueError) and \"SHA256\" in str(e)),\n       wait=wait_exponential(min=2, max=30))\ndef build_ef():\n    return ONNXMiniLM_L6_V2()\n# note: Chroma already retries 3x internally; add outer retries only across longer intervals after clearing the cache dir","preventionTips":["On flaky networks, pre-download the model once, verify its SHA256, and bake ~/.cache/chroma/onnx_models into the image","Fix proxy/TLS-intercepting middleboxes rather than working around the integrity check","Keep ~/.cache on a disk with free space; interrupted writes produce checksum failures","Never disable or patch out the SHA256 check — a persistent mismatch is a security signal"],"tags":["onnx","embedding-function","checksum","download","integrity","chroma"],"backgroundTag":"corrupted-download-checksum","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}