usememos/memos · error
startsWith argument must be a string
Error message
startsWith argument must be a string
What it means
The argument to startsWith() inside a comprehension predicate must be a compile-time string constant. If the argument resolves to a non-string constant (int, bool, etc.), this error is thrown; a non-constant argument produces the wrapped 'startsWith argument must be a constant string' instead.
Source
Thrown at internal/filter/parser.go:970
// buildStartsWithPredicate extracts the pattern from t.startsWith("prefix").
func buildStartsWithPredicate(call *exprv1.Expr_Call, iterVar string) (PredicateExpr, error) {
// Verify the target is the iteration variable
if target := call.Target.GetIdentExpr(); target == nil || target.GetName() != iterVar {
return nil, errors.Errorf("startsWith target must be the iteration variable %q", iterVar)
}
if len(call.Args) != 1 {
return nil, errors.New("startsWith expects exactly one argument")
}
prefix, err := getConstValue(call.Args[0])
if err != nil {
return nil, errors.Wrap(err, "startsWith argument must be a constant string")
}
prefixStr, ok := prefix.(string)
if !ok {
return nil, errors.New("startsWith argument must be a string")
}
return &StartsWithPredicate{Prefix: prefixStr}, nil
}
// 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")View on GitHub (pinned to 14d757ce1f)
Solutions
- Quote the prefix: tag.exists(t, t.startsWith("work"))
- Remember the prefix is a SQL LIKE 'prefix%' pattern, so it must be a literal string
Example fix
// before
`tag.exists(t, t.startsWith(5))`
// after
`tag.exists(t, t.startsWith("work"))` Defensive patterns
Strategy: validation
Validate before calling
var badStartsWith = regexp.MustCompile(`startsWith\s*\(\s*[^"']`)
func validateStartsWith(expr string) error {
if badStartsWith.MatchString(expr) {
return errors.New("startsWith needs a quoted string prefix")
}
return nil
} Try / catch
if err := r.Render(cond); err != nil {
if strings.Contains(err.Error(), "startsWith argument must be a string") {
return userErr("quote the startsWith prefix, e.g. t.startsWith(\"work\")")
}
return err
} Prevention
- Quote prefix literals
- Remember prefixes compile to SQL LIKE 'prefix%' patterns and must be literal strings
When it happens
Trigger: tag.exists(t, t.startsWith(5)) — passing a numeric literal instead of a quoted string; similarly boolean or duration literals.
Common situations: Users write unquoted prefixes or assume startsWith coerces types.
Related errors
- equality argument must be a string
- endsWith 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/275ae6eb1ffe3938.
Report an issue: GitHub.