usememos/memos · error
tags must be compared with string literals
Error message
tags must be compared with string literals
What it means
Each value in tag in [...] must be a string literal. renderTagInList calls expectLiteral on every element and then type-asserts it to string; a non-string literal (int, bool, duration, timestamp) fails this check because JSON tag containment can only match strings.
Source
Thrown at internal/filter/render.go:456
return r.renderScalarInCondition(field, cond.Values)
}
func (r *renderer) renderTagInList(values []ValueExpr) (renderResult, error) {
field, ok := r.schema.ResolveAlias("tag")
if !ok {
return renderResult{}, errors.New("tag attribute is not configured")
}
conditions := make([]string, 0, len(values))
for _, v := range values {
lit, err := expectLiteral(v)
if err != nil {
return renderResult{}, err
}
str, ok := lit.(string)
if !ok {
return renderResult{}, errors.New("tags must be compared with string literals")
}
condition, err := r.renderJSONListContains(field, str)
if err != nil {
return renderResult{}, err
}
conditions = append(conditions, condition.sql)
}
if len(conditions) == 0 {
return renderResult{sql: "1 = 0"}, nil
}
if len(conditions) == 1 {
return renderResult{sql: conditions[0]}, nil
}
return renderResult{
sql: fmt.Sprintf("(%s)", strings.Join(conditions, " OR ")),
}, nilView on GitHub (pinned to 14d757ce1f)
Solutions
- Quote every element: tag in ["1", "2"]
- Keep the IN list homogeneous strings when filtering tags
Example fix
// before `tag in [1, 2]` // after `tag in ["1", "2"]`
Defensive patterns
Strategy: validation
Validate before calling
// Check every IN-list element is a string literal before rendering
for _, v := range inCond.Values {
lit, err := expectLiteral(v)
if err != nil {
return err
}
if _, ok := lit.(string); !ok {
return errors.New("tag IN list must contain only string literals")
}
} Type guard
func allStringLiterals(values []filter.ValueExpr) bool {
for _, v := range values {
lit, ok := v.(*filter.LiteralValue)
if !ok {
return false
}
if _, ok := lit.Value.(string); !ok {
return false
}
}
return true
} Try / catch
if err := r.Render(cond); err != nil {
if strings.Contains(err.Error(), "string literals") {
return userErr("quote every value in the tag IN list")
}
return err
} Prevention
- Quote all elements of tag IN lists, including numeric-looking tags
- Keep tag lists homogeneous strings in filter expressions
When it happens
Trigger: tag in [1, 2] or tag in [true, "work"] — mixing numeric/boolean literals into the IN list; also duration('24h') in tag.
Common situations: Numeric tag names written unquoted; copy-pasting mixed-type lists from other filter examples.
Related errors
- comparison must start with a field reference or supported fu
- size() expects one argument
- size() argument must be a field
- IN operator requires a field on the left-hand side
- text match argument must be a string
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/83395bbb13745d61.
Report an issue: GitHub.