usememos/memos · error
endsWith argument must be a string
Error message
endsWith argument must be a string
What it means
The argument to endsWith() in a comprehension predicate must be a compile-time string constant. A constant of any other type (int, bool, timestamp, ...) triggers this error; non-constant operands surface as the wrapped 'endsWith argument must be a constant string'.
Source
Thrown at internal/filter/parser.go:993
// buildEndsWithPredicate extracts the pattern from t.endsWith("suffix").
func buildEndsWithPredicate(call *exprv1.Expr_Call, iterVar string) (PredicateExpr, error) {
if target := call.Target.GetIdentExpr(); target == nil || target.GetName() != iterVar {
return nil, errors.Errorf("endsWith target must be the iteration variable %q", iterVar)
}
if len(call.Args) != 1 {
return nil, errors.New("endsWith expects exactly one argument")
}
suffix, err := getConstValue(call.Args[0])
if err != nil {
return nil, errors.Wrap(err, "endsWith argument must be a constant string")
}
suffixStr, ok := suffix.(string)
if !ok {
return nil, errors.New("endsWith argument must be a string")
}
return &EndsWithPredicate{Suffix: suffixStr}, nil
}
// buildContainsPredicate extracts the pattern from t.contains("substring").
func buildContainsPredicate(call *exprv1.Expr_Call, iterVar string) (PredicateExpr, error) {
if target := call.Target.GetIdentExpr(); target == nil || target.GetName() != iterVar {
return nil, errors.Errorf("contains target must be the iteration variable %q", iterVar)
}
if len(call.Args) != 1 {
return nil, errors.New("contains expects exactly one argument")
}
substring, err := getConstValue(call.Args[0])
if err != nil {
return nil, errors.Wrap(err, "contains argument must be a constant string")View on GitHub (pinned to 14d757ce1f)
Solutions
- Quote the suffix: tag.exists(t, t.endsWith(".draft"))
- Check the field is a string list before using endsWith
Example fix
// before
`tag.exists(t, t.endsWith(2024))`
// after
`tag.exists(t, t.endsWith(".draft"))` Defensive patterns
Strategy: validation
Validate before calling
var badEndsWith = regexp.MustCompile(`endsWith\s*\(\s*[^"']`)
func validateEndsWith(expr string) error {
if badEndsWith.MatchString(expr) {
return errors.New("endsWith needs a quoted string suffix")
}
return nil
} Try / catch
if err := r.Render(cond); err != nil {
if strings.Contains(err.Error(), "endsWith argument must be a string") {
return userErr("quote the endsWith suffix, e.g. t.endsWith(\".draft\")")
}
return err
} Prevention
- Quote suffix literals
- Keep suffixes as plain strings, not numeric or boolean literals
When it happens
Trigger: tag.exists(t, t.endsWith(2024)) or tag.all(t, t.endsWith(true)) — non-string literal passed to endsWith.
Common situations: Unquoted suffix values; users copying numeric suffix patterns from docs of other systems.
Related errors
- equality argument must be a string
- startsWith argument must be a string
- contains argument must be a string
- text match argument must be a string
- comprehension accumulator must be initialized with a constan
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/83124ef7e81c2040.
Report an issue: GitHub.