Tencent/WeKnora · error
empty logical condition
Error message
empty logical condition
What it means
convertLogicalCondition builds a Milvus boolean expression from an AND/OR condition's children. It returns this error when, after iterating over the condition's children, no convertResult was produced (e.g. the children array was empty), so there is no expression string to emit.
Source
Thrown at internal/application/repository/retriever/milvus/filter.go:132
if childRes == nil || childRes.exprStr == "" {
continue
}
if condResult == nil {
condResult = childRes
continue
}
condResult.exprStr = fmt.Sprintf(
"(%s) %s (%s)",
condResult.exprStr,
strings.ToLower(cond.Operator),
childRes.exprStr,
)
maps.Copy(condResult.params, childRes.params)
}
if condResult == nil {
return nil, fmt.Errorf("empty logical condition")
}
return condResult, nil
}
func (c *filter) convertCondition(
cond *universalFilterCondition,
counter *int,
) (*convertResult, error) {
if cond == nil {
return nil, fmt.Errorf("milvus filter condition is nil")
}
switch cond.Operator {
case operatorEqual, operatorNotEqual, operatorGreaterThan,
operatorGreaterThanOrEqual, operatorLessThan,
operatorLessThanOrEqual, operatorLike, operatorNotLike:
return c.convertComparisonCondition(cond, counter)
case operatorAnd, operatorOr:
return c.convertLogicalCondition(cond, counter)View on GitHub (pinned to 988cbb0330)
Solutions
- Ensure AND/OR conditions contain at least one child condition in their Value array
- Validate the filter before calling Convert, rejecting logical operators with empty condition arrays
- Log the full condition tree to find the empty logical node
Example fix
// before
cond := &UniversalFilterCondition{Operator: "AND", Value: []*UniversalFilterCondition{}}
res, err := f.Convert(ctx, cond) // error: empty logical condition
// after
cond := &UniversalFilterCondition{Operator: "AND", Value: []*UniversalFilterCondition{
{Field: "age", Operator: "GREATER_THAN", Value: 18},
}}
res, err := f.Convert(ctx, cond) Defensive patterns
Strategy: validation
Validate before calling
func validLogical(c *UniversalFilterCondition) bool {
if c.Operator != "AND" && c.Operator != "OR" { return true }
conds, ok := c.Value.([]*UniversalFilterCondition)
return ok && len(conds) > 0
} Type guard
func isLogicalWithChildren(c *UniversalFilterCondition) bool {
conds, ok := c.Value.([]*UniversalFilterCondition)
return ok && len(conds) > 0
} Try / catch
res, err := f.Convert(ctx, cond)
if err != nil {
if strings.Contains(err.Error(), "empty logical condition") {
return nil, fmt.Errorf("filter has an AND/OR node with no sub-conditions: %w", err)
}
return nil, err
} Prevention
- Never construct AND/OR conditions with an empty Value slice
- Add a unit test covering empty logical nodes
- Centralize filter construction in a builder that enforces >=1 child
When it happens
Trigger: Calling Convert with a logical (AND/OR) condition whose Value array is empty, or whose children all fail silently to produce a result.
Common situations: Deserializing a filter from JSON where "value": [] for an AND/OR node; programmatically building nested filters and appending no sub-conditions.
Related errors
- milvus filter condition is nil
- unsupported comparison operator: %s
- invalid logical condition value type
- 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/ebfaa6fe4acda383.
Report an issue: GitHub.