siyuan-note/siyuan · error

filter must not be null

Error message

filter must not be null

What it means

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.

Solutions

  1. Remove null entries from the filters array before sending; send only fully formed filter objects.
  2. Validate every element (including nested group filters) is a non-null object before the call.
  3. If a placeholder is needed to keep positions, build the array without the placeholder instead of using null.

Example fix

// before
{"relationFilters": [{"column": "a"}, null]}
// after
{"relationFilters": [{"column": "a"}]}
Defensive patterns

Strategy: validation

Validate before calling

// JS: reject null entries anywhere in the filter tree
function hasNullFilter(list) { return list.some(f => f == null || (f.filters && hasNullFilter(f.filters))); }
if (hasNullFilter(filters)) throw new Error("filter must not be null");

Type guard

function isValidFilter(f) { return f != null && typeof f === "object" && (!f.filters || f.filters.every(isValidFilter)); }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/f6c6605534abf487. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view_key_config.go:161

	if av.KeyTypeRelation != relationKey.Type || nil == relationKey.Relation {
		return errors.New("filters require a configured relation field")
	}
	dest, err := av.ParseAttributeView(relationKey.Relation.AvID)
	if nil != err {
		return err
	}
	var filters []*av.ViewFilter
	if err = decodeAttributeViewKeyConfig(value, &filters); nil != err {
		return err
	}
	if err = av.ValidateFilterDepth(filters); nil != err {
		return err
	}
	var validate func([]*av.ViewFilter) error
	validate = func(items []*av.ViewFilter) error {
		for _, filter := range items {
			if nil == filter {
				return errors.New("filter must not be null")
			}
			if filter.IsGroup() {
				if av.FilterCombinationAnd != filter.Combination && av.FilterCombinationOr != filter.Combination {
					return errors.New("filter group requires and/or combination")
				}
				if err := validate(filter.Filters); nil != err {
					return err
				}
			} else if _, err := dest.GetKey(filter.Column); nil != err {
				return fmt.Errorf("invalid filter target field: %s", filter.Column)
			}
		}
		return nil
	}
	return validate(filters)
}

// decodeAttributeViewKeyConfig 拒绝未知字段及空值,防止拼写错误被当作成功更新。

View on GitHub (pinned to 9f775e8a12)