usememos/memos · error

unsupported comprehension type (supported: exists, all, exis

Error message

unsupported comprehension type (supported: exists, all, exists_one)

What it means

detectComprehensionKind recognized a comprehension but could not match it to any supported macro. The parser only supports exists() (accu=false + ||), all() (accu=true + &&), and exists_one() (accu=int 0 + ternary). Any other comprehension shape — map(), filter(), list macros, sum(), etc. — falls through to this error.

Source

Thrown at internal/filter/parser.go:872

		}
	}

	// all() starts with true and uses AND (&&) in the loop step.
	if accuInit.GetBoolValue() {
		if step := comp.LoopStep.GetCallExpr(); step != nil && step.Function == "_&&_" {
			return ComprehensionAll, nil
		}
	}

	// exists_one() starts at int(0) and increments via a conditional (predicate ?
	// accu + 1 : accu) in the loop step.
	if _, isInt := accuInit.GetConstantKind().(*exprv1.Constant_Int64Value); isInt {
		if step := comp.LoopStep.GetCallExpr(); step != nil && step.Function == "_?_:_" {
			return ComprehensionExistsOne, nil
		}
	}

	return "", errors.New("unsupported comprehension type (supported: exists, all, exists_one)")
}

// extractPredicate extracts the predicate expression from the comprehension loop step.
func extractPredicate(comp *exprv1.Expr_Comprehension, _ Schema) (PredicateExpr, error) {
	// The loop step is: @result || predicate(t) for exists
	//                or: @result && predicate(t) for all
	step := comp.LoopStep.GetCallExpr()
	if step == nil {
		return nil, errors.New("comprehension loop step must be a call expression")
	}

	// exists/all: accu || predicate  /  accu && predicate  -> predicate is arg[1].
	// exists_one: predicate ? accu + 1 : accu               -> predicate is arg[0].
	var predicateExpr *exprv1.Expr
	if step.Function == "_?_:_" {
		if len(step.Args) != 3 {
			return nil, errors.New("exists_one loop step must have three arguments")
		}

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Restrict list predicates to exists(), all(), or exists_one(), e.g. tag.exists(t, t.startsWith("work"))
  2. Replace map()/filter() intent with the supported predicate functions ==, startsWith, endsWith, contains inside exists/all

Example fix

// before
`tag.map(t, t.upperAscii()).exists(t, t == "WORK")`

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

Strategy: validation

Validate before calling

var unsupportedMacros = regexp.MustCompile(`\.\s*(map|filter|sum|take|drop)\s*\(`)

func validateFilter(expr string) error {
    if unsupportedMacros.MatchString(expr) {
        return errors.New("only exists/all/exists_one macros are supported")
    }
    return nil
}

Try / catch

if err := r.Render(cond); err != nil {
    if strings.Contains(err.Error(), "unsupported comprehension type") {
        return userErr("filter uses an unsupported list macro; use exists, all, or exists_one")
    }
    return err
}

Prevention

When it happens

Trigger: CEL filter using an unsupported macro on a list field, e.g. tag.map(t, t.size()) , tag.filter(...), tag.sum(...) or exists_one written against a loop step the pattern matcher does not recognize (e.g. accu init is int but loop step is not _?_:_).

Common situations: Users familiar with full CEL try list transformations in the memo filter bar; API clients send filters copied from other CEL-based systems (Envoy, Firebase rules) that allow map/filter macros.

Related errors


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