Tencent/WeKnora · error
invalid logical condition value type
Error message
invalid logical condition value type
What it means
convertLogicalCondition type-asserts cond.Value to []*universalFilterCondition to obtain the child conditions of a logical node. If Value is non-nil but holds any other type, it returns 'invalid logical condition value type'. This protects the converter from malformed filter trees where a logical node's payload was built with the wrong element type.
Source
Thrown at internal/application/repository/retriever/milvus/filter.go:105
}
paramName := c.convertParamName(cond.Field, counter)
return &convertResult{
exprStr: fmt.Sprintf("%s %s {%s}", condField, operator, paramName),
params: map[string]any{paramName: cond.Value},
}, nil
}
func (c *filter) convertLogicalCondition(
cond *universalFilterCondition,
counter *int,
) (*convertResult, error) {
if cond.Value == nil {
return nil, fmt.Errorf("milvus filter condition is nil")
}
conds, ok := cond.Value.([]*universalFilterCondition)
if !ok {
return nil, fmt.Errorf("invalid logical condition value type")
}
var condResult *convertResult
for _, childCond := range conds {
childRes, err := c.convertCondition(childCond, counter)
if err != nil {
return nil, err
}
if childRes == nil || childRes.exprStr == "" {
continue
}
if condResult == nil {
condResult = childRes
continue
}
condResult.exprStr = fmt.Sprintf(
"(%s) %s (%s)",View on GitHub (pinned to 988cbb0330)
Solutions
- Ensure logical conditions are constructed only via the helper that stores []*universalFilterCondition in Value.
- Fix the caller constructing the tree so children are appended as *universalFilterCondition pointers.
- If input comes from JSON, decode into the typed condition structs first, then build the tree; never pass raw decoded values.
- Add a constructor (e.g. newLogicalCond(op string, children []*universalFilterCondition)) and forbid direct Value assignment.
Example fix
// before
node := &universalFilterCondition{Operator: "AND", Value: children} // children is []universalFilterCondition
// after
ptrs := make([]*universalFilterCondition, len(children))
for i := range children {
ptrs[i] = &children[i]
}
node := &universalFilterCondition{Operator: "AND", Value: ptrs} Defensive patterns
Strategy: type-guard
Validate before calling
if kids, ok := cond.Value.([]*universalFilterCondition); !ok || len(kids) == 0 {
return errors.New("logical condition must carry []*universalFilterCondition children")
} Type guard
func asChildConditions(v any) ([]*universalFilterCondition, bool) {
kids, ok := v.([]*universalFilterCondition)
return kids, ok && len(kids) > 0
} Prevention
- Store logical children exclusively as []*universalFilterCondition via a dedicated constructor.
- Decode JSON filters into typed structs before assembling the tree.
- Never assign raw decoded values (map[string]any, []any) to Value.
- Add a unit test asserting the converter round-trips every logical node type.
When it happens
Trigger: Building a logical condition whose Value is []universalFilterCondition (no pointer), []*someOtherCondType, a single *universalFilterCondition, or a raw map/slice from JSON decoding — any non-[]*universalFilterCondition payload.
Common situations: JSON/YAML filter decoding producing map[string]any instead of typed conditions; refactors changing the condition struct without updating group builders; mixing condition types from two different filter packages.
Related errors
- milvus filter condition is nil
- unsupported comparison operator: %s
- empty logical condition
- unsupported operator: %v
- in operator value must be a slice with at least one value: %
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/dce8a9a522f655f6.
Report an issue: GitHub.