siyuan-note/siyuan · error

inline style [%s] must use the same fields in light and dark

Error message

inline style [%s] must use the same fields in light and dark themes

What it means

Light and dark themes of one inline style must be field-symmetric: if light sets Color, dark must set Color too, and likewise for BackgroundColor (presence must match, though values may differ). Mixed field usage would make rendering inconsistent between color schemes, so normalization rejects the style.

Source

Thrown at kernel/model/inline_style.go:696

		if style.Light == nil || style.Dark == nil {
			return nil, fmt.Errorf("inline style [%s] must define light and dark themes", id)
		}

		light, err := normalizeInlineStyleTheme(style.Light)
		if err != nil {
			return nil, fmt.Errorf("invalid light theme of inline style [%s]: %w", id, err)
		}
		dark, err := normalizeInlineStyleTheme(style.Dark)
		if err != nil {
			return nil, fmt.Errorf("invalid dark theme of inline style [%s]: %w", id, err)
		}
		lightColor, lightBackground := light.Color != "", light.BackgroundColor != ""
		darkColor, darkBackground := dark.Color != "", dark.BackgroundColor != ""
		if !lightColor && !lightBackground {
			return nil, fmt.Errorf("inline style [%s] must define color or backgroundColor", id)
		}
		if lightColor != darkColor || lightBackground != darkBackground {
			return nil, fmt.Errorf("inline style [%s] must use the same fields in light and dark themes", id)
		}

		ret = append(ret, &InlineStyle{ID: id, Name: name, Hidden: style.Hidden, Light: light, Dark: dark})
	}
	return ret, nil
}

func normalizeInlineStyleBuiltin(builtin *InlineStyleBuiltin) (ret *InlineStyleBuiltin, err error) {
	ret = newEmptyInlineStyleBuiltin()
	if builtin == nil {
		return ret, nil
	}

	colorIndexes := make(map[int]struct{}, len(builtin.Colors))
	for _, color := range builtin.Colors {
		if color == nil {
			return nil, errors.New("builtin color must not be null")
		}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Make both themes use the same field(s): if light uses Color, set Color in dark as well (values may differ per mode).
  2. Normalize programmatically: compute lightColor/lightBackground booleans and darkColor/darkBackground booleans and fix the dark entry to match before saving.
  3. Rewrite the on-disk inline-styles JSON so the light and dark theme objects use identical field sets.

Example fix

// before
Light: &InlineStyleTheme{Color: "#ff0000"},
Dark:  &InlineStyleTheme{BackgroundColor: "#3a2a2a"} // field mismatch
// after
Light: &InlineStyleTheme{Color: "#ff0000"},
Dark:  &InlineStyleTheme{Color: "#ff6b6b"}
Defensive patterns

Strategy: validation

Validate before calling

for (const s of styles) { const l = !!s.Light.Color, lb = !!s.Light.BackgroundColor, d = !!s.Dark.Color, db = !!s.Dark.BackgroundColor; if (l !== d || lb !== db) throw new Error(`style ${s.ID} uses different fields in light and dark themes`); }

Type guard

const themesAreFieldSymmetric = (s: InlineStyle): boolean => (!!s.Light.Color === !!s.Dark.Color) && (!!s.Light.BackgroundColor === !!s.Dark.BackgroundColor);

Try / catch

try { await saveStyles(styles) } catch (e) { if (/same fields in light and dark/.test(String(e))) { /* align the dark theme's field usage with light, then retry */ } }

Prevention

When it happens

Trigger: setInlineStylesData receives an InlineStyle where, e.g., Light sets only Color while Dark sets only BackgroundColor, or one theme sets both fields and the other only one; loadInlineStyles reads such an asymmetric entry from disk.

Common situations: Manually editing dark-mode JSON and changing which field is used; scripts generating dark themes by swapping roles (background-on-dark, color-on-light); copy-pasting theme objects and deleting a field in one of them.

Related errors


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