usememos/memos · error

equality argument must be a string

Error message

equality argument must be a string

What it means

The == predicate inside a comprehension must compare the iteration variable to a compile-time string constant. After locating the constant side, getConstValue extracts its value; if the value exists but is not a string (e.g. int, bool, duration, timestamp), this error is returned. (A non-constant operand instead yields the wrapped 'equality argument must be a constant string'.)

Source

Thrown at internal/filter/parser.go:941

	var constExpr *exprv1.Expr
	switch {
	case isIterVarExpr(call.Args[0], iterVar):
		constExpr = call.Args[1]
	case isIterVarExpr(call.Args[1], iterVar):
		constExpr = call.Args[0]
	default:
		return nil, errors.Errorf("equality predicate must compare against the iteration variable %q", iterVar)
	}

	value, err := getConstValue(constExpr)
	if err != nil {
		return nil, errors.Wrap(err, "equality argument must be a constant string")
	}

	valueStr, ok := value.(string)
	if !ok {
		return nil, errors.New("equality argument must be a string")
	}

	return &EqualsPredicate{Value: valueStr}, nil
}

func isIterVarExpr(expr *exprv1.Expr, iterVar string) bool {
	target := expr.GetIdentExpr()
	return target != nil && target.GetName() == iterVar
}

// 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 {

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Quote the comparison value: tag.exists(t, t == "42")
  2. Verify the field being iterated is a string-list field (like tag) and use string literals

Example fix

// before
`tag.exists(t, t == 42)`

// after
`tag.exists(t, t == "42")`
Defensive patterns

Strategy: validation

Validate before calling

// Ensure == comparisons inside macros use string literals
var nonStringEq = regexp.MustCompile(`==\s*([^"'\s][^,)]*)`)

func validateEqStrings(expr string) error {
    if nonStringEq.MatchString(expr) {
        return errors.New("compare tags with double-quoted string literals")
    }
    return nil
}

Try / catch

if err := r.Render(cond); err != nil {
    if strings.Contains(err.Error(), "equality argument must be a string") {
        return userErr("tag comparisons must use quoted string values")
    }
    return err
}

Prevention

When it happens

Trigger: tag.exists(t, t == 42) or tag.exists(t, t == true) — comparing the iterated string (tag) to a numeric or boolean literal.

Common situations: Users assume tags can be numbers; copy-pasting filters from other systems where tag lists are typed differently.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/4834edeaa5624d3e. Report an issue: GitHub.