siyuan-note/siyuan · error

invalid appearance ID

Error message

invalid appearance ID

What it means

loadBootAppearance validates the appearance ID before attempting to read the appearance's directory under the plugin. An ID that doesn't match the strict kebab-case pattern ^[a-z0-9]+(-[a-z0-9]+)*$ is rejected immediately with 'invalid appearance ID', preventing path/lookup issues from malformed names.

Solutions

  1. Rename the appearance directory inside the plugin to lowercase kebab-case (e.g. my-appearance)
  2. Validate the ID against ^[a-z0-9]+(-[a-z0-9]+)*$ before calling
  3. Get a valid ID from GetBootAppearances rather than constructing it from the filesystem or user input

Example fix

// before
app, err := model.GetBootAppearanceByID("plugin", "Dark Theme")
// after
app, err := model.GetBootAppearanceByID("plugin", "dark-theme")
Defensive patterns

Strategy: validation

Validate before calling

var idRe = regexp.MustCompile(`^[a-z0-9]+(-[a-z0-9]+)*$`)
if !idRe.MatchString(appearanceID) { return errors.New("invalid appearance ID") }

Type guard

func isValidAppearanceID(id string) bool { return regexp.MustCompile(`^[a-z0-9]+(-[a-z0-9]+)*$`).MatchString(id) }

Try / catch

app, err := loadBootAppearance(dir, pkg, id)
if err != nil && strings.Contains(err.Error(), "invalid appearance ID") {
  // skip or normalize the ID and retry
}

Prevention

When it happens

Trigger: getBootAppearanceByID or GetBootAppearances reaching loadBootAppearance with an appearance ID containing uppercase letters, underscores, spaces, slashes, empty string, or repeated/leading/trailing hyphens.

Common situations: Directory names inside the plugin's appearance folder that aren't kebab-case (e.g. 'MyTheme', 'old_theme'); IDs derived from user input or filenames; plugin packages shipped with non-conforming appearance folder names.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/6adc41efed7036e9. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/boot_appearance.go:377

	if err != nil {
		return
	}
	current := defaultBootAppearanceSelection()
	if err = gulu.JSON.UnmarshalJSON(data, &current); err != nil || current != expected {
		return
	}
	data, err = gulu.JSON.MarshalIndentJSON(defaultBootAppearanceSelection(), "", "\t")
	if err != nil {
		return
	}
	if err = filelock.WriteFile(configPath, data); err != nil {
		logging.LogWarnf("clear invalid boot appearance selection failed: %s", err)
	}
}

func loadBootAppearance(pluginDir string, pkg *bazaar.Package, appearanceID string) (ret *BootAppearance, err error) {
	if !isValidBootAppearanceID(appearanceID) {
		err = errors.New("invalid appearance ID")
		return
	}
	appearanceDir := filepath.Join(pluginDir, bootAppearanceDirName, appearanceID)
	if err = validateBootAppearancePackage(pluginDir, appearanceDir); err != nil {
		return
	}
	manifestPath, _, resolveErr := validateBootAppearanceResource(pluginDir, appearanceDir, bootAppearanceManifestName, "manifest")
	if resolveErr != nil {
		err = resolveErr
		return
	}
	data, readErr := filelock.ReadFile(manifestPath)
	if readErr != nil {
		err = readErr
		return
	}
	manifest := &bootAppearanceManifest{}
	if err = gulu.JSON.UnmarshalJSON(data, manifest); err != nil {

View on GitHub (pinned to 9f775e8a12)