chroma-core/chroma · critical · ValueError

Downloaded file {fname} does not match expected SHA256 hash.

Error message

Downloaded file {fname} does not match expected SHA256 hash. Corrupted download or malicious file.

What it means

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.

Source

Thrown at chromadb/utils/embedding_functions/onnx_mini_lm_l6_v2.py:122

            fname: The path to save the model to.
            chunk_size: The chunk size to use when downloading.
        """
        with httpx.stream("GET", url) as resp:
            total = int(resp.headers.get("content-length", 0))
            with open(fname, "wb") as file, self.tqdm(
                desc=str(fname),
                total=total,
                unit="iB",
                unit_scale=True,
                unit_divisor=1024,
            ) as bar:
                for data in resp.iter_bytes(chunk_size=chunk_size):
                    size = file.write(data)
                    bar.update(size)

        if not _verify_sha256(fname, self._MODEL_SHA256):
            os.remove(fname)
            raise ValueError(
                f"Downloaded file {fname} does not match expected SHA256 hash. Corrupted download or malicious file."
            )

    # Use pytorches default epsilon for division by zero
    # https://pytorch.org/docs/stable/generated/torch.nn.functional.normalize.html
    def _normalize(self, v: npt.NDArray[np.float32]) -> npt.NDArray[np.float32]:
        """
        Normalize a vector.

        Args:
            v: The vector to normalize.

        Returns:
            The normalized vector.
        """
        norm = np.linalg.norm(v, axis=1)
        # Handle division by zero
        norm[norm == 0] = 1e-12

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. 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
  2. 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
  3. 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
  4. If the hash mismatch persists on a known-good network, treat it as a potential tampering signal: do not disable verification, investigate the source

Example fix

// shell — clear a corrupted cache and retry on a stable network
rm -rf ~/.cache/chroma/onnx_models/all-MiniLM-L6-v2
python -c "from chromadb.utils.embedding_functions.onnx_mini_lm_l6_v2 import ONNXMiniLM_L6_V2; ONNXMiniLM_L6_V2()"
Defensive patterns

Strategy: retry

Validate before calling

import hashlib
from pathlib import Path
EXPECTED = "913d7300ceae3b2dbc2c50d1de4baacab4be7b9380491c27fab7418616a16ec3"
model_dir = Path.home() / ".cache" / "chroma" / "onnx_models" / "all-MiniLM-L6-v2"
for f in model_dir.glob("*") if model_dir.exists() else []:
    h = hashlib.sha256(f.read_bytes()).hexdigest()
    if f.name.endswith(".tar.gz") and h != EXPECTED:
        f.unlink()  # remove corrupt cache so Chroma re-downloads
# construction now downloads fresh if needed

Try / catch

from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential
@retry(reraise=True, stop=stop_after_attempt(3),
       retry=retry_if_exception(lambda e: isinstance(e, ValueError) and "SHA256" in str(e)),
       wait=wait_exponential(min=2, max=30))
def build_ef():
    return ONNXMiniLM_L6_V2()
# note: Chroma already retries 3x internally; add outer retries only across longer intervals after clearing the cache dir

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/11cb5508ddf8d5e3. Report an issue: GitHub.