{"record":{"id":"d6fdc7f9fe72034d","repo":"siyuan-note/siyuan","slug":"attribute-view-custom-color-must-not-be-null","errorCode":null,"errorMessage":"attribute view custom color must not be null","messagePattern":"attribute view custom color must not be null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/av/color.go","lineNumber":129,"sourceCode":"\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tindexes[normalized.Index] = struct{}{}\n\t\tret = append(ret, normalized)\n\t}\n\n\tsort.Slice(ret, func(i, j int) bool {\n\t\treturn ret[i].Index < ret[j].Index\n\t})\n\tif nil == ret {\n\t\tret = []*AttributeViewCustomColor{}\n\t}\n\treturn\n}\n\nfunc normalizeAttributeViewCustomColor(color *AttributeViewCustomColor) (ret *AttributeViewCustomColor, err error) {\n\tif nil == color {\n\t\treturn nil, errors.New(\"attribute view custom color must not be null\")\n\t}\n\tif color.Index < CustomColorMinIndex || CustomColorMaxIndex < color.Index {\n\t\treturn nil, fmt.Errorf(\"attribute view custom color index [%d] is out of range [%d, %d]\",\n\t\t\tcolor.Index, CustomColorMinIndex, CustomColorMaxIndex)\n\t}\n\n\tret = &AttributeViewCustomColor{Index: color.Index, Hidden: color.Hidden}\n\tret.Light, err = normalizeAttributeViewColorTheme(color.Light)\n\tif nil != err {\n\t\treturn nil, fmt.Errorf(\"invalid light theme of attribute view custom color [%d]: %w\", color.Index, err)\n\t}\n\tret.Dark, err = normalizeAttributeViewColorTheme(color.Dark)\n\tif nil != err {\n\t\treturn nil, fmt.Errorf(\"invalid dark theme of attribute view custom color [%d]: %w\", color.Index, err)\n\t}\n\treturn\n}\n","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/av/color.go#L111-L147","documentation":"normalizeAttributeViewCustomColor rejects a nil AttributeViewCustomColor pointer. A null entry in the color list cannot be normalized or persisted, so it is treated as an explicit error rather than skipped.","triggerScenarios":"Passing a slice containing nil elements to NormalizeAttributeViewCustomColors, e.g. from JSON decoding of a palette that contains literal null entries, or building the slice with a fixed-length array leaving trailing nils.","commonSituations":"Hand-edited palette JSON containing `null` array items; make([]*AttributeViewCustomColor, n) with unfilled slots; config merging that inserts nil placeholders.","solutions":["Filter out nil entries from the slice before calling NormalizeAttributeViewCustomColors","Fix the source JSON to remove null items","Initialize all slice elements when constructing colors programmatically"],"exampleFix":"// before\nret, err := av.NormalizeAttributeViewCustomColors(colors, true)\n// after\nvar filtered []*av.AttributeViewCustomColor\nfor _, c := range colors {\n    if c != nil { filtered = append(filtered, c) }\n}\nret, err := av.NormalizeAttributeViewCustomColors(filtered, true)","handlingStrategy":"type-guard","validationCode":"for i, c := range colors {\n    if c == nil { return fmt.Errorf(\"nil color at %d\", i) }\n}","typeGuard":"func validColors(colors []*av.AttributeViewCustomColor) []*av.AttributeViewCustomColor {\n    var out []*av.AttributeViewCustomColor\n    for _, c := range colors { if c != nil { out = append(out, c) } }\n    return out\n}","tryCatchPattern":"if _, err := av.NormalizeAttributeViewCustomColors(colors, true); err != nil {\n    if strings.Contains(err.Error(), \"must not be null\") { colors = validColors(colors) }\n}","preventionTips":["Filter nils after JSON decoding of palette files","Use append instead of pre-sized slices when filling colors","Treat decoded null JSON items as corrupt input"],"tags":["attribute-view","null","validation"],"backgroundTag":"null-argument","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}