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

  1. Pass one of the exact canonical constants: conf.UpdateChannelStable ("stable"), conf.UpdateChannelBeta ("beta"), or conf.UpdateChannelAlpha ("alpha").
  2. If the channel comes from user/UI input, validate it with isValidUpdateChannel(channel) before calling SetUpdateChannel, and surface a friendly localized error otherwise.
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/fb39893576e8a6ea. Report an issue: GitHub.