usememos/memos · error

arithmetic requires two arguments

Error message

arithmetic requires two arguments

What it means

evaluateNumeric constant-folds arithmetic (_+_, _-_, _*_, _/_, _%_) on timestamps, durations, and integers, and requires the binary operator to have exactly two operands. A hand-constructed AST with wrong arity is rejected here; text-parsed filters normally cannot produce this because the CEL grammar fixes binary arity.

Solutions

  1. Ensure binary arithmetic calls always carry exactly two args when constructing or rewriting ASTs
  2. Re-serialize the AST to a filter string and re-parse to validate
  3. Add unit tests asserting arity invariants after each rewrite pass

Example fix

// before (rewrite dropped an operand)
call.Args = call.Args[:1]

// after
call.Args = []*exprv1.Expr{left, right}
Defensive patterns

Strategy: validation

Validate before calling

// Go (AST builder/rewriter): enforce binary arity
switch fn {
case "_+_", "_-_", "_*_", "_/_%_":
    if len(args) != 2 { return errors.New("binary op needs two operands") }
}

Prevention

When it happens

Trigger: Directly building an exprv1.Expr_Call for arithmetic with len(Args) != 2, e.g. an AST optimizer collapsing '_-_' to one operand after removing a foldable term.

Common situations: AST manipulation code (partial evaluators, filter rewriters) that mutates Args arrays; integrating third-party CEL tooling that emits non-canonical call nodes.

Related errors


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

Appendix: source

Thrown at internal/filter/parser.go:548

		if ident.GetName() == "now" {
			return now.Unix(), true, nil
		}
		return 0, false, nil
	}

	call := expr.GetCallExpr()
	if call == nil {
		return 0, false, nil
	}

	switch call.Function {
	case "timestamp":
		return evaluateTimestamp(call)
	case "duration":
		return evaluateDuration(call)
	case "_+_", "_-_", "_*_", "_/_", "_%_":
		if len(call.Args) != 2 {
			return 0, false, errors.New("arithmetic requires two arguments")
		}
		left, ok, err := evaluateNumeric(call.Args[0], now)
		if err != nil {
			return 0, false, err
		}
		if !ok {
			return 0, false, nil
		}
		right, ok, err := evaluateNumeric(call.Args[1], now)
		if err != nil {
			return 0, false, err
		}
		if !ok {
			return 0, false, nil
		}
		switch call.Function {
		case "_+_":
			return left + right, true, nil

View on GitHub (pinned to 14d757ce1f)