gastownhall/beads · error

count comparison requires integer value, got %q: %w

Error message

count comparison requires integer value, got %q: %w

What it means

For a count aggregate (children(x).count(...) or steps.complete N), the comparison value must parse as an integer via strconv.Atoi. The count of matching steps is an int, so a non-numeric expected value cannot be compared and evaluation aborts with this wrapped error.

Source

Thrown at internal/formula/condition.go:376

	case "count":
		count := 0
		for _, s := range steps {
			// For steps.complete pattern, field is the status to count
			if c.AggregateOver == "steps" && (c.Field == "complete" || c.Field == "failed" || c.Field == "pending" || c.Field == "in_progress") {
				if s.Status == c.Field {
					count++
				}
			} else {
				satisfied, _ := matchStep(s, c.Field, OpEqual, c.Value)
				if satisfied {
					count++
				}
			}
		}
		expected, err := strconv.Atoi(c.Value)
		if err != nil {
			return nil, fmt.Errorf("count comparison requires integer value, got %q: %w", c.Value, err)
		}
		satisfied, reason := compareInt(count, c.Operator, expected)
		return &ConditionResult{
			Satisfied: satisfied,
			Reason:    reason,
		}, nil
	}

	return nil, fmt.Errorf("unknown aggregate function: %s", c.AggregateFunc)
}

func (c *Condition) evaluateExternal(ctx *ConditionContext) (*ConditionResult, error) {
	switch c.ExternalType {
	case "file.exists":
		path := c.ExternalArg
		// Substitute variables
		for k, v := range ctx.Vars {
			path = strings.ReplaceAll(path, "{{"+k+"}}", v)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use a plain integer literal in the comparison: `children(task).count(status == 'complete') >= 3`
  2. Strip quotes/whitespace from the value before constructing the Condition.Value field
  3. Parse with strconv.Atoi yourself (or ValidateRange-style check) before calling Evaluate to fail fast with a clearer message

Example fix

// before
cond, _ := formula.ParseCondition("children(t).count(status == 'complete') >= 'three'")
res, err := cond.Evaluate(ctx) // count comparison requires integer value, got "three"
// after
cond, _ := formula.ParseCondition("children(t).count(status == 'complete') >= 3")
res, err := cond.Evaluate(ctx)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := strconv.Atoi(cond.Value); err != nil {
	return fmt.Errorf("count condition needs integer value, got %q", cond.Value)
}
res, err := cond.Evaluate(ctx)

Type guard

func isIntString(s string) bool { _, err := strconv.Atoi(s); return err == nil }

Try / catch

res, err := cond.Evaluate(ctx)
if err != nil && strings.Contains(err.Error(), "count comparison requires integer value") {
	return fmt.Errorf("fix the count literal in %q", cond.Raw)
}
return res, err

Prevention

When it happens

Trigger: Evaluate() on a Type=aggregate condition with AggregateFunc="count" whose Value is non-integer — e.g. `children(task).count(status == 'complete') >= three`, or a quoted value like `'3'` that includes stray characters/whitespace.

Common situations: Hand-writing the trailing comparison of a count expression with a word instead of a number; variable substitution injecting a non-numeric string; copying a float (3.0) or value with a unit (3x); programmatic construction where Value was populated from the inner condition's quoted string instead of the trailing comparison.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/fc4465308f6019c4. Report an issue: GitHub.