termux/termux-app · error · GradleException

Wrong checksum for %s: expected: %s, actual: %s

Error message

Wrong checksum for %s: expected: %s, actual: %s

What it means

Thrown by the downloadBootstrap Gradle task when the SHA-256 checksum of the downloaded (or locally present) bootstrap zip does not match the expected checksum passed to the task. The mismatched file is deleted and the build aborts. This protects against corrupted or tampered bootstrap artifacts.

Source

Thrown at app/build.gradle:206

    }

    def remoteUrl = "https://github.com/termux/termux-packages/releases/download/bootstrap-" + version + "/bootstrap-" + arch + ".zip"
    logger.quiet("Downloading " + remoteUrl + " ...")

    file.parentFile.mkdirs()
    def out = new BufferedOutputStream(new FileOutputStream(file))

    def connection = new URL(remoteUrl).openConnection()
    connection.setInstanceFollowRedirects(true)
    def digestStream = new java.security.DigestInputStream(connection.inputStream, digest)
    out << digestStream
    out.close()

    def checksum = new BigInteger(1, digest.digest()).toString(16)
    while (checksum.length() < 64) { checksum = "0" + checksum }
    if (checksum != expectedChecksum) {
        file.delete()
        throw new GradleException("Wrong checksum for " + remoteUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
    }
}

clean {
    doLast {
        def tree = fileTree(new File(projectDir, 'src/main/cpp'))
        tree.include 'bootstrap-*.zip'
        tree.each { it.delete() }
    }
}

task downloadBootstraps() {
    doLast {
        def packageVariant = project.ext.packageVariant
        if (packageVariant == "apt-android-7") {
            def version = "2026.02.12-r1" + "%2B" + "apt.android-7"
            downloadBootstrap("aarch64", "ea2aeba8819e517db711f8c32369e89e7c52cee73e07930ff91185e1ab93f4f3", version)
            downloadBootstrap("arm", "a38f4d3b2f735f83be2bf54eff463e86dc32a3e2f9f861c1557c4378d249c018", version)

View on GitHub (pinned to 3df69d1da1)

Solutions

  1. Update the expectedChecksum in build.gradle to match the current bootstrap release for the target arch/version.
  2. Delete the cached bootstrap-<arch>.zip under src/main/cpp so it re-downloads fresh.
  3. Verify the remoteUrl points to the correct arch and release.
  4. Recompute the SHA-256 of a known-good zip and set it as expectedChecksum.

Example fix

// before (stale checksum)
downloadBootstrap('aarch64', 'oldsha256...', '0.118.0')

// after (recompute and update)
// shasum -a 256 bootstrap-aarch64.zip  ->  <newhash>
downloadBootstrap('aarch64', '<newhash>', '0.118.0')
Defensive patterns

Strategy: retry

Validate before calling

def knownSha = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(Files.readAllBytes(knownGoodZip.toPath()))).toString(16)
while (knownSha.length() < 64) knownSha = "0" + knownSha
assert knownSha == expectedChecksum : "expectedChecksum is stale"

Try / catch

// Re-download once on checksum mismatch, then fail
int attempts = 0
while (true) {
    try {
        downloadBootstrap(arch, expectedChecksum, version)
        break
    } catch (GradleException e) {
        if (++attempts > 1 || !(e.message?.contains("Wrong checksum"))) throw e
        new File(projectDir, "src/main/cpp/bootstrap-${arch}.zip").delete()
    }
}

Prevention

When it happens

Trigger: The remote bootstrap URL serves a different zip than expected (newer build, wrong arch, truncated); the expected checksum in build.gradle is stale/wrong; a network proxy/CDN returned an error page; the local cached zip is corrupt.

Common situations: Bootstrap was re-released with a new checksum but build.gradle still has the old one; partial download due to network drop; mirror served wrong content; manual local zip that is out of date.

Related errors


AI-assisted analysis of termux/termux-app@3df69d1da1 (2026-08-13). Data as JSON: /api/errors/d0dcb691544a8f00. Report an issue: GitHub.