{"record":{"id":"06a78dfe2425bdd0","repo":"commaai/openpilot","slug":"raw-hash-mismatch-raw-hash-hexdigest-lower","errorCode":null,"errorMessage":"Raw hash mismatch '{raw_hash.hexdigest().lower()}'","messagePattern":"Raw hash mismatch '(.+?)'","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"openpilot/common/hardware/comma/agnos.py","lineNumber":176,"sourceCode":"def extract_compressed_image(target_slot_number: int, partition: dict, cloudlog):\n  path = get_partition_path(target_slot_number, partition)\n  downloader = StreamingDecompressor(partition['url'])\n\n  with open(path, 'wb+') as out:\n    # Flash partition\n    last_p = 0\n    raw_hash = hashlib.sha256()\n    f = unsparsify if partition['sparse'] else noop\n    for chunk in f(downloader):\n      raw_hash.update(chunk)\n      out.write(chunk)\n      p = int(out.tell() / partition['size'] * 100)\n      if p != last_p:\n        last_p = p\n        print(f\"Installing {partition['name']}: {p}\", flush=True)\n\n    if raw_hash.hexdigest().lower() != partition['hash_raw'].lower():\n      raise Exception(f\"Raw hash mismatch '{raw_hash.hexdigest().lower()}'\")\n\n    if downloader.sha256.hexdigest().lower() != partition['hash'].lower():\n      raise Exception(\"Uncompressed hash mismatch\")\n\n    if out.tell() != partition['size']:\n      raise Exception(\"Uncompressed size mismatch\")\n\n    os.sync()\n\n\ndef flash_partition(target_slot_number: int, partition: dict, cloudlog, standalone=False):\n  cloudlog.info(f\"Downloading and writing {partition['name']}\")\n\n  if verify_partition(target_slot_number, partition):\n    cloudlog.info(f\"Already flashed {partition['name']}\")\n    return\n\n  # Clear hash before flashing in case we get interrupted","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/hardware/comma/agnos.py#L158-L194","documentation":"After uncompressing and unsparsifying a partition image, verify/flash code compares the SHA-256 of the raw (unsparsified) output against partition['hash_raw']. A mismatch means the bytes written differ from the manifest — corruption in the sparse stream, truncation, or a wrong/man-in-the-middled download.","triggerScenarios":"verify_partition()/flash_partition() where the unsparsified output hash differs from the manifest's hash_raw — e.g. a chunk was dropped or reordered by the streaming decompressor.","commonSituations":"Corrupted download over flaky network; partial write after power loss; manifest and image versions out of sync.","solutions":["Retry the AGNOS flash — transient corruption is the most common cause","Check network reliability / use a wired or stable connection for large firmware downloads","Ensure the manifest and images come from the same release (no partial update)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        flash_partition(slot, partition, cloudlog)\n        break\n    except Exception as e:\n        if \"mismatch\" not in str(e):\n            raise","preventionTips":["Re-download and re-flash from scratch on any hash mismatch","Never continue boot after a failed partition flash"],"tags":["firmware","agnos","hash-mismatch","flashing"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}