henrygd/beszel · error

failed to open release for checksum verification

Error message

failed to open release for checksum verification: %w

What it means

Once the digest parses, verifyAssetChecksum opens the downloaded asset file to hash it. If os.Open fails — the file doesn't exist, permissions deny read, or it's a directory — the error is wrapped with this message. This means the problem is with the local downloaded file, not the digest.

Solutions

  1. Check the file exists and is readable at the path referenced in the wrapped error: `ls -la <path>`.
  2. Fix permissions on the DataDir (default os.TempDir()) so the user running the update can read the downloaded asset.
  3. Check for antivirus/EDR quarantine of the downloaded archive and whitelist the update directory.
  4. Retry the update — a transient FS error or cleanup race may have removed the file between download and verify.

Example fix

// before
sudo -u otheruser ./beszel-agent update   // cannot read files created by root in /tmp
// after
./beszel-agent update                      // run as the same user that owns DataDir files
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Stat(cfg.DataDir); err != nil || !fi.IsDir() {
    return errors.New("DataDir must be an existing, accessible directory")
}

Try / catch

updated, err := ghupdate.Update(cfg)
if err != nil && strings.Contains(err.Error(), "failed to open release for checksum verification") {
    log.Printf("downloaded asset unreadable (%v); check permissions/AV and retry", err)
    // retry once after confirming the DataDir is writable
}

Prevention

When it happens

Trigger: ghupdate.Update -> update -> verifyAssetChecksum when the downloaded asset file at releaseDir/<asset.Name> cannot be opened: download was skipped or cleaned up, disk permissions restrict read access, or antivirus/EDR quarantined the freshly downloaded binary.

Common situations: Read-only or noexec-mounted DataDir (e.g. /tmp mounted noexec with odd permission setups); running the updater as a different user than the downloader; antivirus removing downloaded archives before verification; full or failing disk.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/acea3baa991bb56c. Report an issue: GitHub.

Appendix: source

Thrown at internal/ghupdate/checksum.go:29

)

func verifyAssetChecksum(path, digest string) error {
	algorithm, expectedHex, ok := strings.Cut(digest, ":")
	if !ok || algorithm == "" || expectedHex == "" {
		return fmt.Errorf("invalid release digest %q", digest)
	}
	if !strings.EqualFold(algorithm, "sha256") {
		return fmt.Errorf("unsupported release digest algorithm %q", algorithm)
	}

	expected, err := hex.DecodeString(expectedHex)
	if err != nil || len(expected) != sha256.Size {
		return fmt.Errorf("invalid SHA-256 release digest %q", digest)
	}

	file, err := os.Open(path)
	if err != nil {
		return fmt.Errorf("failed to open release for checksum verification: %w", err)
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return fmt.Errorf("failed to calculate release checksum: %w", err)
	}
	actual := hash.Sum(nil)
	if !bytes.Equal(actual, expected) {
		return fmt.Errorf("release checksum mismatch: expected %s, got %s", expectedHex, hex.EncodeToString(actual))
	}

	return nil
}

View on GitHub (pinned to b38fb7dafa)