siyuan-note/siyuan · error · ErrFilterTooDeep

filter nesting depth exceeds the maximum allowed

Error message

filter nesting depth exceeds the maximum allowed

What it means

ErrFilterTooDeep is returned by ValidateFilterDepth / validateFilterNodeDepth (kernel/av/filter.go:152-173) when a filter group tree nests deeper than MaxFilterNestingDepth = 3 (kernel/av/av_fix.go:29). It guards against stack exhaustion and pathological evaluation on the recursive filter structure introduced with spec-5 grouped filters.

Solutions

  1. Flatten the filter tree: since spec 5 a single root group exists (normalizeFiltersAsRoot), push leaf conditions into fewer, wider groups instead of deep chains
  2. Cap recursion at 3 when generating filters client-side and AND-merge anything deeper into the nearest group
  3. Run av.ValidateFilterDepth(filters) before persisting if you construct []*av.ViewFilter directly in Go

Example fix

// before: nesting groups 5 deep
filters := group(and, group(or, group(and, group(or, leaves...))))

// after: flatten to max depth 3, widen the root group
filters := group(and,
    leaf(cond1), leaf(cond2),
    group(or, leaf(cond3), leaf(cond4)),
)
Defensive patterns

Strategy: validation

Validate before calling

func clampFilterDepth(node *av.ViewFilter, depth int) *av.ViewFilter {
    if nil == node || !node.IsGroup() || depth >= 3 {
        return node // stop nesting here; merge leaves into this group
    }
    for i, child := range node.Filters {
        node.Filters[i] = clampFilterDepth(child, depth+1)
    }
    return node
}
_ = av.ValidateFilterDepth(filters) // final check before persisting

Type guard

func isFilterTooDeep(err error) bool {
    return errors.Is(err, av.ErrFilterTooDeep)
}

Prevention

When it happens

Trigger: Submitting a setAttrViewFilters operation whose ViewFilter group chain (Filter.Combination groups containing groups) exceeds depth 3; replaying or hand-crafting a deeply nested filters array in the .av.json; a plugin building filters recursively from user input without a depth cap.

Common situations: Programmatically composed filter trees (e.g. converting a boolean expression to nested AND/OR groups) that exceed 3 levels; imported or synced database definitions that were produced by a tool without the depth limit.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/055de086a32d7980. Report an issue: GitHub.

Appendix: source

Thrown at kernel/av/av.go:1302

	}
	return
}

func GetAttributeViewI18n(key string) string {
	return util.AttrViewLangs[util.Lang][key].(string)
}

var (
	ErrAttributeViewNotFound  = errors.New("attribute view not found")
	ErrInvalidAttributeViewID = errors.New("invalid attribute view id")
	ErrInvalidBoxID           = errors.New("invalid box id")
	ErrViewNotFound           = errors.New("view not found")
	ErrKeyNotFound            = errors.New("key not found")
	ErrItemNotFound           = errors.New("item not found")
	ErrWrongLayoutType        = errors.New("wrong layout type")
	ErrInvalidColumnAlign     = errors.New("invalid column align")
	ErrSpecTooNew             = errors.New("attribute view spec is too new")
	ErrFilterTooDeep          = errors.New("filter nesting depth exceeds the maximum allowed")
)

const (
	NodeAttrNameAvs        = "custom-avs"                 // 用于标记块所属的属性视图,逗号分隔 av id
	NodeAttrView           = "custom-sy-av-view"          // 用于标记块所属的属性视图视图 view id Database block support specified view https://github.com/siyuan-note/siyuan/issues/10443
	NodeAttrVisibleViewIDs = "custom-sy-av-visible-views" // 用于标记数据库块显示的视图 ID,逗号分隔
	NodeAttrViewStaticText = "custom-sy-av-s-text"        // 用于标记块所属的属性视图静态文本 Database-bound block primary key supports setting static anchor text https://github.com/siyuan-note/siyuan/issues/10049

	NodeAttrViewNames = "av-names" // 用于临时标记块所属的属性视图名称,空格分隔
)

View on GitHub (pinned to afa823b6b4)