siyuan-note/siyuan · error
update channel is invalid
Error message
update channel is invalid
What it means
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.
Source
Thrown at kernel/model/update_channel.go:60
return conf.UpdateChannelStable
}
config := &globalUpdateConf{}
if err = gulu.JSON.UnmarshalJSON(data, config); err != nil {
logging.LogWarnf("parse update channel config [%s] failed: %s", configPath, err)
return conf.UpdateChannelStable
}
if !isValidUpdateChannel(config.Channel) {
logging.LogWarnf("invalid update channel [%s], using stable channel", config.Channel)
return conf.UpdateChannelStable
}
return config.Channel
}
// SetUpdateChannel 校验并保存应用级更新通道。
func SetUpdateChannel(channel string) error {
if !isValidUpdateChannel(channel) {
return errors.New("update channel is invalid")
}
data, err := gulu.JSON.MarshalIndentJSON(&globalUpdateConf{Channel: channel}, "", " ")
if err != nil {
return err
}
configPath := globalUpdateConfPath()
if err = os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
return err
}
if err = filelock.WriteFile(configPath, data); err != nil {
return err
}
Conf.System.UpdateChannel = channel
return nil
}
func globalUpdateConfPath() string {View on GitHub (pinned to 251596fc0d)
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.
Example fix
// before
err := model.SetUpdateChannel(reqChannel) // reqChannel = "Stable"
// after
reqChannel = strings.ToLower(strings.TrimSpace(reqChannel))
if !isValidChannel(reqChannel) {
return errors.New("channel must be stable, beta, or alpha")
}
err := model.SetUpdateChannel(reqChannel) Defensive patterns
Strategy: validation
Validate before calling
// Validate before calling SetUpdateChannel.
allowed := map[string]bool{"stable": true, "beta": true, "alpha": true}
ch := strings.ToLower(strings.TrimSpace(input))
if !allowed[ch] {
return fmt.Errorf("invalid update channel %q; want stable|beta|alpha", input)
}
return model.SetUpdateChannel(ch) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- update channel is invalid
- unsupported server type: %s
- command is required for stdio server
- icon [%s] not exists or not available
- theme [%s] not exists or not available for light mode
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/fb39893576e8a6ea.
Report an issue: GitHub.