siyuan-note/siyuan · error

inline style must not be null

Error message

inline style must not be null

What it means

normalizeInlineStyles validates the workspace inline-style list before saving or loading it. A nil element inside the styles slice is rejected outright because the normalizer dereferences style.ID/Name/Light/Dark and a null entry would represent corrupt configuration. The whole save/load operation fails fast with this error.

Source

Thrown at kernel/model/inline_style.go:651

		if _, ok := hidden[index]; !ok {
			ret = append(ret, index)
		}
	}
	if len(ret) == 0 {
		return []int{neutralAVColorIndex}
	}
	return ret
}

func normalizeInlineStyles(styles []*InlineStyle, generateIDs bool) (ret []*InlineStyle, err error) {
	if maxInlineStyles < len(styles) {
		return nil, fmt.Errorf("inline styles count exceeds the %d item limit", maxInlineStyles)
	}
	ret = make([]*InlineStyle, 0, len(styles))
	ids := make(map[string]struct{}, len(styles))
	for _, style := range styles {
		if style == nil {
			return nil, errors.New("inline style must not be null")
		}

		id := strings.TrimSpace(style.ID)
		if id == "" && generateIDs {
			for {
				id = ast.NewNodeID()
				if _, exists := ids[id]; !exists {
					break
				}
			}
		}
		if !ast.IsNodeIDPattern(id) {
			return nil, fmt.Errorf("invalid inline style ID [%s]", id)
		}
		if _, exists := ids[id]; exists {
			return nil, fmt.Errorf("duplicate inline style ID [%s]", id)
		}
		ids[id] = struct{}{}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Remove null entries from the styles array before calling the set API (filter on the client or in a preprocessing step).
  2. Fix the inline-styles JSON file on disk (remove the null element) so loadInlineStyles succeeds.
  3. Fix the producer code that appends to the slice to skip nil items instead of relying on later filtering.

Example fix

// before
styles := make([]*InlineStyle, 2)
styles[0] = &InlineStyle{ID: "20240101120000-abcdefg", Name: "mark"}
api.SetInlineStyles(styles) // styles[1] is nil -> error
// after
styles := make([]*InlineStyle, 0, 2)
styles = append(styles, &InlineStyle{ID: "20240101120000-abcdefg", Name: "mark"})
api.SetInlineStyles(styles)
Defensive patterns

Strategy: validation

Validate before calling

const filtered = styles.filter(s => s != null); if (filtered.length !== styles.length) throw new Error('style list contains null entries');

Type guard

const isInlineStyle = (s: unknown): s is InlineStyle => !!s && typeof s === 'object' && 'ID' in s;

Try / catch

try { await fetchPost('/api/attr/setInlineStyles', {styles}) } catch (e) { if (String(e).includes('must not be null')) { styles = styles.filter(Boolean); /* retry */ } }

Prevention

When it happens

Trigger: Passing a []*InlineStyle that contains a nil element to setInlineStylesData (e.g. via the API /api/attr/setInlineStyles with a JSON array containing a null), or a persisted inline-styles JSON file whose array contains a null entry read back by loadInlineStyles.

Common situations: Hand-editing or programmatically generating the inline-styles JSON and leaving a trailing/null element in the array; client code building the list with a fixed-size slice where unused slots stay nil; partial JSON merges that insert null placeholders.

Related errors


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