{"record":{"id":"ed2c2edb15b7be4e","repo":"siyuan-note/siyuan","slug":"stable-release-version-is-invalid","errorCode":null,"errorMessage":"stable release version is invalid","messagePattern":"stable release version is invalid","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/updater_release.go","lineNumber":100,"sourceCode":"\tchannel := Conf.System.UpdateChannel\n\tif conf.UpdateChannelStable == channel {\n\t\treturn getStableUpdateRelease(force)\n\t}\n\tif !isValidUpdateChannel(channel) {\n\t\treturn nil, errors.New(\"update channel is invalid\")\n\t}\n\treturn getGitHubUpdateRelease(channel, force)\n}\n\nfunc getStableUpdateRelease(force bool) (*updateRelease, error) {\n\tresult, err := util.GetRhyResult(context.TODO(), force)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tversion, ok := result[\"ver\"].(string)\n\tnormalizedVersion := normalizeReleaseVersion(version)\n\tif !ok || !semver.IsValid(normalizedVersion) || \"\" != semver.Prerelease(normalizedVersion) {\n\t\treturn nil, errors.New(\"stable release version is invalid\")\n\t}\n\tversion = strings.TrimPrefix(normalizedVersion, \"v\")\n\n\trelease := &updateRelease{\n\t\tVersion:    version,\n\t\tReleaseURL: getStableReleaseURL(result, version),\n\t\tPackages:   map[string]*updatePackage{},\n\t}\n\tpkgName := currentInstallPackageName(release.Version)\n\tif \"\" == pkgName {\n\t\treturn release, nil\n\t}\n\tchecksum := getStablePackageChecksum(result, pkgName)\n\tif \"\" == checksum {\n\t\treturn release, nil\n\t}\n\trelease.Packages[pkgName] = &updatePackage{\n\t\tURLs:     getStablePackageURLs(release.Version, pkgName),","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/updater_release.go#L82-L118","documentation":"Returned by getStableUpdateRelease(force) when the cloud 'rhy' endpoint's version field fails validation: the 'ver' key is missing/not a string, normalizeReleaseVersion yields something semver.IsValid rejects, or semver.Prerelease is non-empty (stable channel must not serve a prerelease). This protects the stable channel from serving pre-release or malformed versions.","triggerScenarios":"util.GetRhyResult returned a JSON map whose 'ver' field is missing, null, a non-string, or a non-semver string like \"3.x\" or \"latest\". The endpoint returned a prerelease-tagged version (e.g. \"3.1.0-beta1\") for the stable channel. The endpoint is temporarily returning a placeholder/maintenance payload.","commonSituations":"Cloud service (rhy) degraded or returning a stale/malformed payload during a deployment. CDN cache serving an intermediate bad response. A legitimate stable release whose version string deviates from semver expectations.","solutions":["Retry with force=true to bypass the rhy cache and fetch fresh data.","Switch to the beta or alpha channel, which reads releases from the GitHub API directly and does not depend on the rhy endpoint.","If persistent, check whether the cloud endpoint is in maintenance; report the malformed version to the maintainers."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Fall back to the GitHub channel if the stable cloud endpoint serves a bad version.\nrelease, err := getStableUpdateRelease(force)\nif err != nil {\n    logging.LogWarnf(\"stable release invalid: %s; falling back to GitHub beta\", err)\n    release, err = getGitHubUpdateRelease(conf.UpdateChannelBeta, force)\n}","preventionTips":["Treat the rhy cloud endpoint as best-effort; have a fallback to the GitHub channel.","Avoid force=true spamming the rhy endpoint during outages.","Surface 'update check temporarily unavailable' rather than a hard failure."],"tags":["update","stable-channel","semver","network","cloud-service"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}