{"record":{"id":"eb4e6d63865c4607","repo":"MHSanaei/3x-ui","slug":"xray-checksum-malformed-sha2-256-entry-in-digest","errorCode":null,"errorMessage":"xray checksum: malformed SHA2-256 entry in digest","messagePattern":"xray checksum: malformed SHA2-256 entry in digest","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/server.go","lineNumber":980,"sourceCode":"\t}\n\traw, err := io.ReadAll(io.LimitReader(resp.Body, maxXrayDigestBytes))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"download xray checksum: %w\", err)\n\t}\n\treturn parseXrayDigestSHA256(raw)\n}\n\n// parseXrayDigestSHA256 extracts the lowercase SHA2-256 hex from an XTLS .dgst\n// file, whose lines are \"ALGO= <hex>\" (the relevant one being \"SHA2-256= ...\").\nfunc parseXrayDigestSHA256(dgst []byte) (string, error) {\n\tfor line := range strings.SplitSeq(string(dgst), \"\\n\") {\n\t\trest, ok := strings.CutPrefix(strings.TrimSpace(line), \"SHA2-256=\")\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\th := strings.ToLower(strings.TrimSpace(rest))\n\t\tif len(h) != 64 {\n\t\t\treturn \"\", fmt.Errorf(\"xray checksum: malformed SHA2-256 entry in digest\")\n\t\t}\n\t\treturn h, nil\n\t}\n\treturn \"\", fmt.Errorf(\"xray checksum: no SHA2-256 entry in digest\")\n}\n\nfunc (s *ServerService) UpdateXray(version string) error {\n\tversions, err := s.GetXrayVersions()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !slices.Contains(versions, version) {\n\t\treturn fmt.Errorf(\"xray version %q is not in the fetched release list\", version)\n\t}\n\n\t// 1. Stop xray before doing anything\n\tif err := s.StopXrayService(); err != nil {\n\t\tlogger.Warning(\"failed to stop xray before update:\", err)","sourceCodeStart":962,"sourceCodeEnd":998,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/server.go#L962-L998","documentation":"Returned by parseXrayDigestSHA256 when a line prefixed 'SHA2-256=' exists but the remaining hex value (after trim + lowercase) is not exactly 64 characters. The .dgst format is 'ALGO= <hex>'; a wrong-length value means the file format changed or the content is corrupted. Hard-coded expectation: SHA-256 hex is always 64 chars.","triggerScenarios":"XTLS changes the .dgst line format (e.g. 'SHA2-256= file' multi-entry lines); a corrupted/truncated sidecar that keeps the prefix but mangles the hash; a proxy-rewritten .dgst body.","commonSituations":"Future upstream format drift breaking older panels; content-mangling middleboxes.","solutions":["curl the .dgst URL and inspect the SHA2-256 line's actual shape","Update the panel to a version matching the current .dgst format, or patch parseXrayDigestSHA256 for the new layout","If the body looks mangled, retry without the proxy"],"exampleFix":"// before\nh := strings.ToLower(strings.TrimSpace(rest))\nif len(h) != 64 {\n    return \"\", fmt.Errorf(\"xray checksum: malformed SHA2-256 entry in digest\")\n}\n// after — tolerate 'hash  filename' lines\nif h, _, ok := strings.Cut(rest, \" \"); ok {\n    h = h\n}\nh = strings.ToLower(strings.TrimSpace(strings.Fields(rest)[0]))\nif len(h) != 64 {\n    return \"\", fmt.Errorf(\"xray checksum: malformed SHA2-256 entry in digest\")\n}\n","handlingStrategy":"validation","validationCode":"h := strings.ToLower(strings.TrimSpace(rest))\nif !regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(h) {\n    return fmt.Errorf(\"digest entry not valid SHA-256 hex: %q\", rest)\n}\n","typeGuard":"func isValidSHA256Hex(s string) bool {\n    if len(s) != 64 {\n        return false\n    }\n    for _, c := range s {\n        if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {\n            return false\n        }\n    }\n    return true\n}\n","tryCatchPattern":null,"preventionTips":["Validate digest shape with a hex regex before comparing","Log the offending line when parse guards fire — format drift vs corruption is distinguishable at a glance","Track upstream release-tooling changes when maintaining a parser for their artifacts"],"tags":["xray-update","checksum","parsing"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}