{"record":{"id":"fb39893576e8a6ea","repo":"siyuan-note/siyuan","slug":"update-channel-is-invalid","errorCode":null,"errorMessage":"update channel is invalid","messagePattern":"update channel is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/update_channel.go","lineNumber":60,"sourceCode":"\t\treturn conf.UpdateChannelStable\n\t}\n\n\tconfig := &globalUpdateConf{}\n\tif err = gulu.JSON.UnmarshalJSON(data, config); err != nil {\n\t\tlogging.LogWarnf(\"parse update channel config [%s] failed: %s\", configPath, err)\n\t\treturn conf.UpdateChannelStable\n\t}\n\tif !isValidUpdateChannel(config.Channel) {\n\t\tlogging.LogWarnf(\"invalid update channel [%s], using stable channel\", config.Channel)\n\t\treturn conf.UpdateChannelStable\n\t}\n\treturn config.Channel\n}\n\n// SetUpdateChannel 校验并保存应用级更新通道。\nfunc SetUpdateChannel(channel string) error {\n\tif !isValidUpdateChannel(channel) {\n\t\treturn errors.New(\"update channel is invalid\")\n\t}\n\n\tdata, err := gulu.JSON.MarshalIndentJSON(&globalUpdateConf{Channel: channel}, \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\tconfigPath := globalUpdateConfPath()\n\tif err = os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {\n\t\treturn err\n\t}\n\tif err = filelock.WriteFile(configPath, data); err != nil {\n\t\treturn err\n\t}\n\tConf.System.UpdateChannel = channel\n\treturn nil\n}\n\nfunc globalUpdateConfPath() string {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/update_channel.go#L42-L78","documentation":"Returned by SetUpdateChannel() when the supplied channel string is not one of the allowed update channels. The allowed set is defined by isValidUpdateChannel(): conf.UpdateChannelStable (\"stable\"), conf.UpdateChannelBeta (\"beta\"), or conf.UpdateChannelAlpha (\"alpha\"). Any other value — including empty strings, typos, or casing differences — is rejected before the channel is persisted to ~/.config/siyuan/update.json.","triggerScenarios":"Calling SetUpdateChannel(\"\") (empty), SetUpdateChannel(\"Stable\") (wrong case), SetUpdateChannel(\"nightly\") (unsupported value), or SetUpdateChannel(\"stable \") (trailing whitespace). The HTTP handler that wraps this (typically the system/update channel setter in api/) forwards the user-supplied channel string verbatim.","commonSituations":"A frontend/settings UI passes a localized or display label instead of the canonical channel constant. A plugin or external automation sets the channel from an unvalidated source. A manual edit of the update.json config file drifts from the canonical spelling.","solutions":["Pass one of the exact canonical constants: conf.UpdateChannelStable (\"stable\"), conf.UpdateChannelBeta (\"beta\"), or conf.UpdateChannelAlpha (\"alpha\").","If the channel comes from user/UI input, validate it with isValidUpdateChannel(channel) before calling SetUpdateChannel, and surface a friendly localized error otherwise.","Trim and lowercase the input before validation if the source is free-form text."],"exampleFix":"// before\nerr := model.SetUpdateChannel(reqChannel) // reqChannel = \"Stable\"\n\n// after\nreqChannel = strings.ToLower(strings.TrimSpace(reqChannel))\nif !isValidChannel(reqChannel) {\n    return errors.New(\"channel must be stable, beta, or alpha\")\n}\nerr := model.SetUpdateChannel(reqChannel)","handlingStrategy":"validation","validationCode":"// Validate before calling SetUpdateChannel.\nallowed := map[string]bool{\"stable\": true, \"beta\": true, \"alpha\": true}\nch := strings.ToLower(strings.TrimSpace(input))\nif !allowed[ch] {\n    return fmt.Errorf(\"invalid update channel %q; want stable|beta|alpha\", input)\n}\nreturn model.SetUpdateChannel(ch)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize channel constants — import conf.UpdateChannelStable/Beta/Alpha rather than typing literals.","Validate at the API/UI boundary before the value reaches the kernel.","Add a unit test asserting SetUpdateChannel rejects \"\", \"Stable\", \"nightly\", and accepts the three canonical values."],"tags":["config","update","validation","channel"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}