henrygd/beszel · error

invalid release digest %q

Error message

invalid release digest %q

What it means

verifyAssetChecksum validates the digest string published on the GitHub release asset before hashing the downloaded file. The digest must be in the form "<algorithm>:<hex-value>" (e.g. "sha256:abcd..."); strings.Cut must split on ":" and both halves must be non-empty. When the digest is missing the colon, empty, or only a bare hash without an algorithm prefix, the library rejects it outright rather than guessing.

Source

Thrown at internal/ghupdate/checksum.go:16

package ghupdate

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"strings"
)

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 {

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Ensure releases are published through GitHub Releases so the API populates the asset digest field (GitHub generates sha256 digests automatically).
  2. If using a mirror or proxy, make sure it forwards the release JSON unchanged, including the assets' digest fields.
  3. Verify the digest string format is "sha256:<64 hex chars>" if constructing release metadata manually.

Example fix

// before (manually crafted digest)
digest := "3f2a...c9"            // bare hex, no algorithm prefix
// after
digest := "sha256:3f2a...c9"      // "<algorithm>:<hex>" form expected by verifyAssetChecksum
Defensive patterns

Strategy: validation

Validate before calling

parts := strings.Split(asset.Digest, ":")
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
    return errors.New("release asset digest is missing or malformed; cannot verify download")
}

Try / catch

updated, err := ghupdate.Update(cfg)
if err != nil && strings.Contains(err.Error(), "invalid release digest") {
    log.Printf("release digest missing/malformed (%v); skipping integrity check — update aborted", err)
}

Prevention

When it happens

Trigger: Calling ghupdate.Update (which calls update -> verifyAssetChecksum) when the release asset's Digest field from the GitHub/mirror API response is not in "algorithm:hex" form — empty string, plain hex hash with no "sha256:" prefix, trailing colon, or "sha256:" with no value.

Common situations: A custom release built and uploaded without GitHub's automatic checksum annotations; a proxy/mirror (e.g. gh.beszel.dev or a self-hosted mirror) that strips the digest field; running against a fork repo whose releases lack digests; an API mock or cached response that omitted the digest.

Related errors


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