{"record":{"id":"7e5641872e211024","repo":"siyuan-note/siyuan","slug":"inline-style-must-not-be-null","errorCode":null,"errorMessage":"inline style must not be null","messagePattern":"inline style must not be null","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/inline_style.go","lineNumber":651,"sourceCode":"\t\tif _, ok := hidden[index]; !ok {\n\t\t\tret = append(ret, index)\n\t\t}\n\t}\n\tif len(ret) == 0 {\n\t\treturn []int{neutralAVColorIndex}\n\t}\n\treturn ret\n}\n\nfunc normalizeInlineStyles(styles []*InlineStyle, generateIDs bool) (ret []*InlineStyle, err error) {\n\tif maxInlineStyles < len(styles) {\n\t\treturn nil, fmt.Errorf(\"inline styles count exceeds the %d item limit\", maxInlineStyles)\n\t}\n\tret = make([]*InlineStyle, 0, len(styles))\n\tids := make(map[string]struct{}, len(styles))\n\tfor _, style := range styles {\n\t\tif style == nil {\n\t\t\treturn nil, errors.New(\"inline style must not be null\")\n\t\t}\n\n\t\tid := strings.TrimSpace(style.ID)\n\t\tif id == \"\" && generateIDs {\n\t\t\tfor {\n\t\t\t\tid = ast.NewNodeID()\n\t\t\t\tif _, exists := ids[id]; !exists {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif !ast.IsNodeIDPattern(id) {\n\t\t\treturn nil, fmt.Errorf(\"invalid inline style ID [%s]\", id)\n\t\t}\n\t\tif _, exists := ids[id]; exists {\n\t\t\treturn nil, fmt.Errorf(\"duplicate inline style ID [%s]\", id)\n\t\t}\n\t\tids[id] = struct{}{}","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/inline_style.go#L633-L669","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove null entries from the styles array before calling the set API (filter on the client or in a preprocessing step).","Fix the inline-styles JSON file on disk (remove the null element) so loadInlineStyles succeeds.","Fix the producer code that appends to the slice to skip nil items instead of relying on later filtering."],"exampleFix":"// before\nstyles := make([]*InlineStyle, 2)\nstyles[0] = &InlineStyle{ID: \"20240101120000-abcdefg\", Name: \"mark\"}\napi.SetInlineStyles(styles) // styles[1] is nil -> error\n// after\nstyles := make([]*InlineStyle, 0, 2)\nstyles = append(styles, &InlineStyle{ID: \"20240101120000-abcdefg\", Name: \"mark\"})\napi.SetInlineStyles(styles)","handlingStrategy":"validation","validationCode":"const filtered = styles.filter(s => s != null); if (filtered.length !== styles.length) throw new Error('style list contains null entries');","typeGuard":"const isInlineStyle = (s: unknown): s is InlineStyle => !!s && typeof s === 'object' && 'ID' in s;","tryCatchPattern":"try { await fetchPost('/api/attr/setInlineStyles', {styles}) } catch (e) { if (String(e).includes('must not be null')) { styles = styles.filter(Boolean); /* retry */ } }","preventionTips":["Always build the styles array with append/push, never pre-allocated fixed slots left nil","Filter nulls before serializing the payload","Never hand-edit the inline-styles JSON without re-validating the array"],"tags":["validation","null-value","inline-styles","go"],"backgroundTag":"null-argument","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}