siyuan-note/siyuan · error

provider and appearance must both be empty or non-empty

Error message

provider and appearance must both be empty or non-empty

What it means

SetBootAppearance requires the provider and appearanceID parameters to be consistent: both empty means 'reset to default appearance', both non-empty selects an appearance. Passing exactly one of them (an impossible half-selection) is rejected with this error before any validation or persistence happens.

Source

Thrown at kernel/model/boot_appearance.go:220

	if err != nil {
		return &BootAppearance{Enabled: false}
	}
	if selection.Provider == "" || selection.Appearance == "" {
		return &BootAppearance{Enabled: false}
	}
	return appearance
}

// SetBootAppearance 校验并原子持久化启动页外观选择,两项均为空表示恢复默认。
func SetBootAppearance(provider, appearanceID string) (ret BootAppearanceSelection, err error) {
	if util.ReadOnly {
		return defaultBootAppearanceSelection(), errors.New("read-only mode")
	}
	provider = strings.TrimSpace(provider)
	appearanceID = strings.TrimSpace(appearanceID)
	ret = defaultBootAppearanceSelection()
	if (provider == "") != (appearanceID == "") {
		err = errors.New("provider and appearance must both be empty or non-empty")
		return
	}
	if provider != "" {
		if !bazaar.IsValidPackageName(provider) || !isValidBootAppearanceID(appearanceID) {
			err = ErrBootAppearanceNotFound
			return
		}
		if _, resolveErr := getBootAppearanceByID(provider, appearanceID); resolveErr != nil {
			err = ErrBootAppearanceNotFound
			return
		}
		ret.Provider, ret.Appearance = provider, appearanceID
	}

	data, err := gulu.JSON.MarshalIndentJSON(ret, "", "\t")
	if err != nil {
		return ret, err
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Pass both provider and appearanceID, or pass both as empty strings to reset to the default appearance.
  2. Fix API payloads to include both fields explicitly.
  3. Validate the pair client-side before the call: (provider == "") == (appearanceID == "").
  4. If only the appearance should change, look up the current provider first and send it together with the new id.

Example fix

// before
model.SetBootAppearance("my-theme", "") // half-selection
// after
if reset { provider, id = "", "" }
model.SetBootAppearance(provider, id) // both set or both empty
Defensive patterns

Strategy: validation

Validate before calling

function isConsistentPair(provider, id) { return (provider === '') === (id === '') }

Prevention

When it happens

Trigger: Calling SetBootAppearance("my-theme", "") or SetBootAppearance("", "dark-splash") — after trimming, exactly one argument is empty; API clients that omit one field in the JSON body so it defaults to empty string.

Common situations: Frontend form where only the provider dropdown was chosen but no appearance id; API scripts resetting only one half of the pair; JSON payloads with a missing key instead of an explicit empty string pair.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/4b0b11e7a54ac8ef. Report an issue: GitHub.