{"record":{"id":"82240e9f4272fe5f","repo":"jdx/mise","slug":"context-sha256-mismatch-expected-sha256-g","errorCode":null,"errorMessage":"#{context}: sha256 mismatch (expected #{sha256}, got #{actual})","messagePattern":"#(.+?): sha256 mismatch \\(expected #(.+?), got #(.+?)\\)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"src/system/packages/brew/shim.rb","lineNumber":87,"sourceCode":"\n  # download with redirects into the cache, verify, return the path\n  def fetch(url, sha256, context)\n    raise \"#{context}: missing sha256\" if sha256.to_s.strip.empty?\n    sha256 = sha256.to_s.strip.downcase\n    raise \"#{context}: malformed sha256\" unless sha256.match?(/\\A[0-9a-f]{64}\\z/)\n\n    MISE_BREW_CACHE.mkpath\n    dest = MISE_BREW_CACHE + \"#{sha256}--#{File.basename(URI(url).path)}\"\n    unless dest.file? && Digest::SHA256.file(dest).hexdigest == sha256\n      ohai \"Downloading #{url}\"\n      tmp = Pathname.new(\"#{dest}.incomplete\")\n      URI.open(url, \"rb\", redirect: true) do |remote|\n        tmp.open(\"wb\") { |f| IO.copy_stream(remote, f) }\n      end\n      actual = Digest::SHA256.file(tmp).hexdigest\n      if actual != sha256\n        tmp.unlink\n        raise \"#{context}: sha256 mismatch (expected #{sha256}, got #{actual})\"\n      end\n      tmp.rename(dest)\n    end\n    dest\n  end\n\n  # unpack an archive the way brew stages sources: if the archive contains a\n  # single top-level directory, its contents become the stage root\n  def unpack(archive, dest)\n    dest.mkpath\n    case archive.basename.to_s\n    when /\\.(tar\\.(gz|xz|bz2|zst)|tgz|txz|tbz2?|tar|crate)\\z/i\n      system_or_die \"tar\", \"xf\", archive.to_s, \"-C\", dest.to_s\n    when /\\.zip\\z/i\n      system_or_die \"unzip\", \"-qo\", archive.to_s, \"-d\", dest.to_s\n    when /\\.(gz|xz|bz2)\\z/i\n      data = `#{archive.to_s =~ /xz\\z/ ? \"xz -dc\" : archive.to_s =~ /bz2\\z/ ? \"bzip2 -dc\" : \"gzip -dc\"} #{Shellwords.escape(archive.to_s)}`\n      raise \"failed to decompress #{archive}\" unless $?.success?","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/shim.rb#L69-L105","documentation":"A Ruby raise in the brew shim's fetch: the downloaded archive's SHA-256 does not match the expected digest. The temp file is deleted and the raise aborts the fetch, protecting against corrupted or tampered downloads.","triggerScenarios":"The remote file at `url` changed upstream (re-tagged release), a mirror served a different artifact, network corruption produced a truncated file, or the package definition's sha256 belongs to a different version of the archive.","commonSituations":"Upstream force-pushes a release tag and re-uploads assets; CDN/proxy caching stale or wrong content; developers bumping a version URL without updating the digest.","solutions":["Verify the expected sha256 against the official upstream release notes/checksums file","If the version was bumped, recompute the digest from the new artifact: `curl -sL <url> | shasum -a 256`","Retry the download in case of transient network corruption","If upstream legitimately changed the artifact, update the pinned digest and record why"],"exampleFix":"# before\nsha256 \"b1946ac92492d2347c6235b4d2611184e0b46a1c\"  # stale/other version\n# after\nsha256 \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"  # matches v1.2.3 tarball","handlingStrategy":"retry","validationCode":"expected = Digest::SHA256.file(local_reference).hexdigest\nraise \"digest drift for #{context}\" unless expected == pinned_sha256","typeGuard":null,"tryCatchPattern":"begin\n  retries ||= 0\n  MiseDownload.fetch(url, sha256, context)\nrescue RuntimeError => e\n  raise if (retries += 1) > 2 || e.message.exclude?(\"mismatch\")\n  sleep 2\n  retry\nend","preventionTips":["Cross-check digests against official upstream checksum files","Re-pin digests when bumping versions and note the source","Retry transient downloads before assuming tampering","Prefer immutable, versioned URLs over moving tags"],"tags":["ruby","checksum","integrity","download"],"backgroundTag":"checksum-mismatch","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}