siyuan-note/siyuan · error

invalid style: %w

Error message

invalid style: %w

What it means

When manifest.Style is non-empty, loadBootAppearance validates the CSS file via validateBootAppearanceResource (safe relative path, no symlink, exists, regular file, .css extension, size cap, valid UTF-8). Any failure is wrapped as "invalid style". This guards the style sheet that is injected into the boot screen.

Source

Thrown at kernel/model/boot_appearance.go:448

	if manifest.OfficialUI.ShowLogo != nil {
		ret.OfficialUI.ShowLogo = *manifest.OfficialUI.ShowLogo
	}
	if manifest.OfficialUI.ShowDetails != nil {
		ret.OfficialUI.ShowDetails = *manifest.OfficialUI.ShowDetails
	}
	for _, color := range []string{manifest.OfficialUI.TextColor, manifest.OfficialUI.ProgressColor,
		manifest.OfficialUI.TrackColor} {
		if err = validateOptionalBootAppearanceColor(color); err != nil {
			return nil, err
		}
	}
	ret.OfficialUI.TextColor = manifest.OfficialUI.TextColor
	ret.OfficialUI.ProgressColor = manifest.OfficialUI.ProgressColor
	ret.OfficialUI.TrackColor = manifest.OfficialUI.TrackColor

	if manifest.Style != "" {
		if _, _, err = validateBootAppearanceResource(pluginDir, appearanceDir, manifest.Style, "style"); err != nil {
			return nil, fmt.Errorf("invalid style: %w", err)
		}
		ret.Style = bootAppearanceAssetURL(pkg.Name, appearanceID, manifest.Style)
	}

	layerIDs := map[string]bool{}
	for _, layer := range manifest.Layers {
		if layer == nil || !isValidBootAppearanceID(layer.ID) || layerIDs[layer.ID] {
			err = errors.New("invalid or duplicate layer ID")
			return nil, err
		}
		layerIDs[layer.ID] = true
		if layer.Type != "image" && layer.Type != "video" {
			err = fmt.Errorf("unsupported layer type [%s]", layer.Type)
			return nil, err
		}
		if _, _, err = validateBootAppearanceResource(pluginDir, appearanceDir, layer.Src, layer.Type); err != nil {
			return nil, fmt.Errorf("invalid layer source: %w", err)
		}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check the style value in manifest.json matches the actual CSS filename inside the appearance directory (case-sensitive)
  2. Use a relative path without leading slash, '..' segments, or backslashes, e.g. 'style.css' or 'assets/style.css'
  3. Re-save the CSS as UTF-8 without NUL bytes and shrink it below maxBootAppearanceStyleSize
  4. Replace any symlink in the appearance directory with a real file

Example fix

// before (manifest.json)
{"style": "/boot/style.css"}
// after
{"style": "style.css"}  // file exists at appearances/<id>/style.css
Defensive patterns

Strategy: validation

Validate before calling

function checkStylePath(style) {
  if (!style) return null;
  if (style.startsWith("/") || style.includes("..") || style.includes("\\")) throw new Error("style path must be relative");
  if (!style.toLowerCase().endsWith(".css")) throw new Error("style must be a .css file");
}
// plus: confirm the file exists and is UTF-8 before packaging

Prevention

When it happens

Trigger: GetBootAppearances/getBootAppearanceByID loading a manifest whose style field points to a missing file, a non-.css extension, an absolute or traversal path (../), a symlink, an oversized CSS file, or a file that is not valid UTF-8 / contains NUL bytes.

Common situations: manifest.json references style.css but only styles.css exists (typo); style path written as '/assets/style.css' or '../style.css'; style.css saved as UTF-16 or with a BOM/NUL; CSS file above the size cap; style field points to an image by mistake.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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