MHSanaei/3x-ui · error
download xray checksum: %w
Error message
download xray checksum: %w
What it means
Returned by fetchXrayDigestSHA256 when http.NewRequestWithContext rejects the .dgst URL before any request is sent (%w wraps reqErr). The URL is mechanically built as the asset URL + ".dgst", so failure here means the constructed URL is not parseable — practically only possible when the base asset URL was already malformed or contains illegal characters. On success paths this error is unreachable.
Source
Thrown at internal/web/service/server.go:953
}
if got := hex.EncodeToString(hasher.Sum(nil)); !strings.EqualFold(got, want) {
// User-facing warning: the archive's SHA-256 does not match the official
// release checksum, so the download is corrupted or has been tampered
// with. Abort the install so a bad binary is never run, and tell the user
// to retry/re-download rather than proceed with a mismatched image.
return "", fmt.Errorf("Xray update aborted: the downloaded archive does not match the official SHA-256 checksum, so the image is corrupted or differs from the official release. Please exit and re-download the official image, then try again (expected %s, got %s)", want, got)
}
ok = true
return path, nil
}
// fetchXrayDigestSHA256 downloads the .dgst sidecar XTLS publishes next to each
// release asset and returns the SHA2-256 hex digest it lists.
func (s *ServerService) fetchXrayDigestSHA256(client *http.Client, dgstURL string) (string, error) {
req, reqErr := http.NewRequestWithContext(context.Background(), http.MethodGet, dgstURL, nil)
if reqErr != nil {
return "", fmt.Errorf("download xray checksum: %w", reqErr)
}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("download xray checksum: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("download xray checksum: unexpected HTTP %d", resp.StatusCode)
}
raw, err := io.ReadAll(io.LimitReader(resp.Body, maxXrayDigestBytes))
if err != nil {
return "", fmt.Errorf("download xray checksum: %w", err)
}
return parseXrayDigestSHA256(raw)
}
// parseXrayDigestSHA256 extracts the lowercase SHA2-256 hex from an XTLS .dgst
// file, whose lines are "ALGO= <hex>" (the relevant one being "SHA2-256= ...").View on GitHub (pinned to ad32144c42)
Solutions
- Inspect the exact version string passed to UpdateXray for whitespace/control characters
- Pre-validate versions against the release list (the code already does via slices.Contains) before manual calls
- Treat this error as a code smell: log the URL being built when it fires
Defensive patterns
Strategy: validation
Validate before calling
if _, err := url.ParseRequestURI(dgstURL); err != nil {
return fmt.Errorf("refusing to fetch malformed digest URL %q: %w", dgstURL, err)
}
Prevention
- Sanitize version inputs (allowlist ^v?\d+\.\d+\.\d+$ style) before building URLs
- Gate versions against the fetched release list before constructing download URLs
When it happens
Trigger: A version string with control characters or spaces slotted into the URL template; a corrupted base URL from upstream configuration; test harnesses injecting invalid URLs.
Common situations: Almost never seen in production; appears in tests or when version input is not sanitized before UpdateXray.
Related errors
- invalid host %q
- xray version %q is not in the fetched release list
- unsupported URL scheme %q
- URL host is required
- The new username and password are empty
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/d8bc078e1518abc3.
Report an issue: GitHub.