rust-lang/rust · critical · RuntimeError
hash mismatch for package {path}: {sha1} vs {sha1_known} (kn
Error message
hash mismatch for package {path}: {sha1} vs {sha1_known} (known good) What it means
Raised by Package.download() in android-sdk-manager.py at line 56 when the SHA-1 hash of the downloaded file does not match the expected (pinned) sha1 stored in the Package object. This is a tamper/integrity check for Android SDK packages. The lockfile pins each package's URL and sha1; if the downloaded content differs, the script aborts to prevent using a corrupted or compromised package.
Source
Thrown at src/ci/docker/scripts/android-sdk-manager.py:56
class Package:
def __init__(self, path, url, sha1, deps=None):
if deps is None:
deps = []
self.path = path.strip()
self.url = url.strip()
self.sha1 = sha1.strip()
self.deps = deps
def download(self, base_url):
_, file = tempfile.mkstemp()
url = base_url + self.url
subprocess.run(["curl", "-o", file, url], check=True)
# Ensure there are no hash mismatches
with open(file, "rb") as f:
sha1 = hashlib.sha1(f.read()).hexdigest()
if sha1 != self.sha1:
raise RuntimeError(
"hash mismatch for package "
+ self.path
+ ": "
+ sha1
+ " vs "
+ self.sha1
+ " (known good)"
)
return file
def __repr__(self):
return "<Package " + self.path + " at " + self.url + " (sha1=" + self.sha1 + ")"
def fetch_url(url):
page = urllib.request.urlopen(url)
return page.read()
View on GitHub (pinned to 7088e4b63a)
Solutions
- Re-download the package (delete the temp file / cached copy and retry).
- If the mirror is stale or corrupted, update the lockfile by re-running 'android-sdk-manager.py add-to-lockfile' with the package name to get the current sha1 from Google's repository, then 'update-mirror' to push a fresh copy.
- Verify network/proxy integrity (run curl manually and compare sha1).
- If the Google-side package legitimately changed, update the lockfile sha1 to match the new known-good hash after verifying the source.
Example fix
# before: lockfile pins stale sha1 # packages-lock.txt sdk-tools-linux;4333796.zip <url> <old-sha1> # after: regenerate lockfile python3 android-sdk-manager.py add-to-lockfile packages-lock.txt 'sdk-tools-linux;4333796'
Defensive patterns
Strategy: validation
Validate before calling
# Before relying on a downloaded package, verify its hash
import hashlib
def verify_sha1(filepath, expected_sha1):
with open(filepath, 'rb') as f:
actual = hashlib.sha1(f.read()).hexdigest()
if actual != expected_sha1:
print(f'Hash mismatch: {actual} vs expected {expected_sha1}')
return False
return True Try / catch
try:
path = package.download(base_url)
except RuntimeError as e:
if 'hash mismatch' in str(e):
# Package may be corrupted on the mirror
print(f'Hash mismatch for {package.path}. Consider updating the lockfile.')
print('Run: android-sdk-manager.py add-to-lockfile <lockfile> <package>')
raise Prevention
- Keep the lockfile updated — re-run add-to-lockfile when Google updates packages.
- Verify mirror integrity periodically by spot-checking package hashes.
- Use HTTPS and verify no proxy modifies downloaded content.
When it happens
Trigger: Package.download(base_url) fetches the file via curl at line 51, reads it, computes hashlib.sha1 at line 54, and compares at line 55. If sha1 != self.sha1, RuntimeError is raised at line 56. The expected sha1 comes from the lockfile (path/url/sha1 per line) or from the Google repository XML.
Common situations: A mirrored package on the rust-lang-ci-mirrors S3 bucket was corrupted or replaced; the Google repository updated a package but the lockfile still pins the old sha1; a network/proxy issue corrupted the download; or the mirror bucket content is stale.
Related errors
- package not found: {name}
- extracted directory contains more than one dir
- failed verification
- src/stage0 doesn't contain a checksum for {}. Pre-built arti
- Unrecognized target triple {triple}
AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10).
Data as JSON: /api/errors/a896816735f1f4fd.
Report an issue: GitHub.