siyuan-note/siyuan · error

%s must define light and dark themes

Error message

%s must define light and dark themes

What it means

A theme pair for a builtin color or builtin style is missing one of its two halves: either `light` or `dark` is null. Builtin entries must always supply both themes so the editor can render consistently when the appearance theme mode switches. The description in the message identifies which entry (e.g. "builtin color [3]" or "builtin style [warning]").

Source

Thrown at kernel/model/inline_style.go:793

func normalizeInlineStyleAV(palette *InlineStyleAV, strict bool) (ret *InlineStyleAV, err error) {
	ret = newEmptyInlineStyleAV()
	if palette == nil {
		return ret, nil
	}
	colors, err := av.NormalizeAttributeViewCustomColors(palette.Colors, strict)
	if err != nil {
		return nil, err
	}
	ret.Colors = colors
	ret.Order = av.NormalizeAttributeViewColorOrder(palette.Order, colors)
	return ret, nil
}

func normalizeInlineStyleThemePair(light, dark *InlineStyleTheme, description string) (normalizedLight,
	normalizedDark *InlineStyleTheme, err error) {
	if light == nil || dark == nil {
		return nil, nil, fmt.Errorf("%s must define light and dark themes", description)
	}
	if normalizedLight, err = normalizeInlineStyleTheme(light); err != nil {
		return nil, nil, fmt.Errorf("invalid light theme of %s: %w", description, err)
	}
	if normalizedDark, err = normalizeInlineStyleTheme(dark); err != nil {
		return nil, nil, fmt.Errorf("invalid dark theme of %s: %w", description, err)
	}
	lightColor, lightBackground := normalizedLight.Color != "", normalizedLight.BackgroundColor != ""
	darkColor, darkBackground := normalizedDark.Color != "", normalizedDark.BackgroundColor != ""
	if !lightColor && !lightBackground {
		return nil, nil, fmt.Errorf("%s must define color or backgroundColor", description)
	}
	if lightColor != darkColor || lightBackground != darkBackground {
		return nil, nil, fmt.Errorf("%s must use the same fields in light and dark themes", description)
	}
	return normalizedLight, normalizedDark, nil
}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Add the missing `light` or `dark` theme object to the entry identified by the message prefix.
  2. If both modes should look identical, still provide both objects with the same color/backgroundColor values.
  3. Ensure the writing code does not use omitempty-style behavior on light/dark theme fields.

Example fix

// before
{"index": 2, "light": {"backgroundColor": "#eeeeee"}}
// after
{"index": 2, "light": {"backgroundColor": "#eeeeee"}, "dark": {"backgroundColor": "#222222"}}
Defensive patterns

Strategy: validation

Validate before calling

for (const entry of entries) { // builtin colors and styles
  if (!entry.light || !entry.dark) {
    throw new Error(`${describe(entry)} must define light and dark themes`);
  }
}

Type guard

function hasThemePair(entry) {
  return entry.light != null && entry.dark != null;
}

Prevention

When it happens

Trigger: setInlineStylesData or loadInlineStyles with a builtin color/style entry that omits the `light` or `dark` key, or sets it to null, passed into normalizeInlineStyleThemePair via normalizeInlineStyleBuiltin.

Common situations: JSON hand-authored with only the current theme mode filled in; a serializer with `omitempty` dropping an empty theme object; partially completed edit of inline-styles.json.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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