{"record":{"id":"f6c6605534abf487","repo":"siyuan-note/siyuan","slug":"filter-must-not-be-null","errorCode":null,"errorMessage":"filter must not be null","messagePattern":"filter must not be null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_key_config.go","lineNumber":161,"sourceCode":"\tif av.KeyTypeRelation != relationKey.Type || nil == relationKey.Relation {\n\t\treturn errors.New(\"filters require a configured relation field\")\n\t}\n\tdest, err := av.ParseAttributeView(relationKey.Relation.AvID)\n\tif nil != err {\n\t\treturn err\n\t}\n\tvar filters []*av.ViewFilter\n\tif err = decodeAttributeViewKeyConfig(value, &filters); nil != err {\n\t\treturn err\n\t}\n\tif err = av.ValidateFilterDepth(filters); nil != err {\n\t\treturn err\n\t}\n\tvar validate func([]*av.ViewFilter) error\n\tvalidate = func(items []*av.ViewFilter) error {\n\t\tfor _, filter := range items {\n\t\t\tif nil == filter {\n\t\t\t\treturn errors.New(\"filter must not be null\")\n\t\t\t}\n\t\t\tif filter.IsGroup() {\n\t\t\t\tif av.FilterCombinationAnd != filter.Combination && av.FilterCombinationOr != filter.Combination {\n\t\t\t\t\treturn errors.New(\"filter group requires and/or combination\")\n\t\t\t\t}\n\t\t\t\tif err := validate(filter.Filters); nil != err {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else if _, err := dest.GetKey(filter.Column); nil != err {\n\t\t\t\treturn fmt.Errorf(\"invalid filter target field: %s\", filter.Column)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\treturn validate(filters)\n}\n\n// decodeAttributeViewKeyConfig 拒绝未知字段及空值，防止拼写错误被当作成功更新。","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_key_config.go#L143-L179","documentation":"After decoding the filters array into []*av.ViewFilter, validateAttributeViewKeyFilters recursively walks the filter tree (including nested groups) and rejects any nil element with 'filter must not be null'. JSON arrays like [null] decode to a nil pointer entry, which this check catches.","triggerScenarios":"Sending {\"relationFilters\": [null]} or a nested group containing null, e.g. {\"filters\": [null, {...}]} inside a group filter; a serializer emits null placeholders for skipped filters.","commonSituations":"Programmatic filter construction appends nil entries; a template that joins filter objects leaves an empty slot producing null; JSON produced by another language maps missing objects to null inside arrays.","solutions":["Remove null entries from the filters array before sending; send only fully formed filter objects.","Validate every element (including nested group filters) is a non-null object before the call.","If a placeholder is needed to keep positions, build the array without the placeholder instead of using null."],"exampleFix":"// before\n{\"relationFilters\": [{\"column\": \"a\"}, null]}\n// after\n{\"relationFilters\": [{\"column\": \"a\"}]}","handlingStrategy":"validation","validationCode":"// JS: reject null entries anywhere in the filter tree\nfunction hasNullFilter(list) { return list.some(f => f == null || (f.filters && hasNullFilter(f.filters))); }\nif (hasNullFilter(filters)) throw new Error(\"filter must not be null\");","typeGuard":"function isValidFilter(f) { return f != null && typeof f === \"object\" && (!f.filters || f.filters.every(isValidFilter)); }","tryCatchPattern":"try { await updateKeyConfig(avID, keyID, { relationFilters: filters }); } catch (e) { if (String(e).includes(\"filter must not be null\")) { throw new TypeError(\"Filters array contains a null entry\"); } throw e; }","preventionTips":["Filter out null entries (filters.filter(Boolean)) before sending","Validate nested group filters recursively","Fix generators/serializers that emit null placeholders for skipped filters"],"tags":["null-value","filters","attribute-view"],"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"}