{"record":{"id":"2ff3ab667cef4184","repo":"microsoft/aspire","slug":"checksum-validation-failed-expected-expectedchecksum-actual","errorCode":null,"errorMessage":"Checksum validation failed. Expected: {expectedChecksum}, Actual: {actualChecksum}","messagePattern":"Checksum validation failed\\. Expected: (.+?), Actual: (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Utils/CliDownloader.cs","lineNumber":217,"sourceCode":"        using var response = await s_httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cts.Token);\n        response.EnsureSuccessStatusCode();\n\n        await using var fileStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.None);\n        await response.Content.CopyToAsync(fileStream, cts.Token);\n    }\n\n    private static async Task ValidateChecksumAsync(string archivePath, string checksumPath, CancellationToken cancellationToken)\n    {\n        var expectedChecksum = (await File.ReadAllTextAsync(checksumPath, cancellationToken)).Trim().ToLowerInvariant();\n\n        using var sha512 = SHA512.Create();\n        await using var fileStream = new FileStream(archivePath, FileMode.Open, FileAccess.Read, FileShare.Read);\n        var hashBytes = await sha512.ComputeHashAsync(fileStream, cancellationToken);\n        var actualChecksum = Convert.ToHexString(hashBytes).ToLowerInvariant();\n\n        if (expectedChecksum != actualChecksum)\n        {\n            throw new InvalidOperationException($\"Checksum validation failed. Expected: {expectedChecksum}, Actual: {actualChecksum}\");\n        }\n    }\n}\n","sourceCodeStart":199,"sourceCodeEnd":221,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Utils/CliDownloader.cs#L199-L221","documentation":"After downloading the CLI archive, the downloader computes the file's SHA-512 hash and compares it against the expected checksum published alongside the download. When the computed hex string differs from the expected value, ValidateChecksumAsync throws InvalidOperationException, treating the downloaded artifact as corrupt or tampered.","triggerScenarios":"CliDownloader.DownloadLatestCliAsync downloads an archive whose SHA-512 hash does not match the expected checksum fetched from the release metadata - corrupted download, truncated file, CDN/proxy content mutation, or checksum-published-version mismatch.","commonSituations":"Flaky corporate proxies or SSL-inspecting firewalls rewriting responses, interrupted downloads (partial file), fetching a newer CLI binary than the checksum file describes (race during release publication), or antivirus software modifying the archive on disk.","solutions":["Retry the download (delete the partially downloaded archive first); transient truncation is the most common cause.","Bypass or disable proxies/SSL inspection for the download URL and try again from a different network if possible.","Check whether a release was just published (checksum and binary temporarily out of sync) and retry later or pin a previous CLI version.","Verify your disk/AV setup if the mismatch reproduces consistently on the same machine."],"exampleFix":"// before\nawait cliDownloader.DownloadLatestCliAsync(installDir);\n// after\ntry\n{\n    await cliDownloader.DownloadLatestCliAsync(installDir);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Checksum validation failed\"))\n{\n    Console.Error.WriteLine($\"Download integrity check failed: {ex.Message}. Retrying...\");\n    await cliDownloader.DownloadLatestCliAsync(installDir);\n}","handlingStrategy":"retry","validationCode":"long len = new FileInfo(archivePath).Length;\nif (len == 0 || len < expectedMinSize) throw new IOException(\"Downloaded archive looks truncated; refusing checksum check.\");","typeGuard":null,"tryCatchPattern":"try { await DownloadLatestCliAsync(dir); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Checksum validation failed\")) { // delete archive, retry with backoff\nFile.Delete(archivePath); await Task.Delay(2000); await DownloadLatestCliAsync(dir); }","preventionTips":["Retry downloads with exponential backoff and always delete partial files first.","Prefer stable networks; avoid SSL-inspecting proxies for binary downloads.","Avoid triggering downloads seconds after a release publication (checksum/binary skew)."],"tags":["checksum","sha512","download","integrity","cli"],"backgroundTag":"checksum-mismatch","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}