{"record":{"id":"dc22d47d1678536a","repo":"gastownhall/beads","slug":"unknown-aggregate-function-s","errorCode":null,"errorMessage":"unknown aggregate function: %s","messagePattern":"unknown aggregate function: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/condition.go","lineNumber":385,"sourceCode":"\t\t\t} else {\n\t\t\t\tsatisfied, _ := matchStep(s, c.Field, OpEqual, c.Value)\n\t\t\t\tif satisfied {\n\t\t\t\t\tcount++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\texpected, err := strconv.Atoi(c.Value)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"count comparison requires integer value, got %q: %w\", c.Value, err)\n\t\t}\n\t\tsatisfied, reason := compareInt(count, c.Operator, expected)\n\t\treturn &ConditionResult{\n\t\t\tSatisfied: satisfied,\n\t\t\tReason:    reason,\n\t\t}, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"unknown aggregate function: %s\", c.AggregateFunc)\n}\n\nfunc (c *Condition) evaluateExternal(ctx *ConditionContext) (*ConditionResult, error) {\n\tswitch c.ExternalType {\n\tcase \"file.exists\":\n\t\tpath := c.ExternalArg\n\t\t// Substitute variables\n\t\tfor k, v := range ctx.Vars {\n\t\t\tpath = strings.ReplaceAll(path, \"{{\"+k+\"}}\", v)\n\t\t}\n\t\t_, err := os.Stat(path)\n\t\texists := err == nil\n\t\treturn &ConditionResult{\n\t\t\tSatisfied: exists,\n\t\t\tReason:    fmt.Sprintf(\"file %q exists: %v\", path, exists),\n\t\t}, nil\n\n\tcase \"env\":","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/condition.go#L367-L403","documentation":"evaluateAggregate supports exactly three aggregate functions: all, any, and count. If Condition.AggregateFunc holds anything else, evaluation falls through the switch and returns this error. ParseCondition only emits these three names, so this arises from programmatically built conditions.","triggerScenarios":"Evaluate() on a Type=aggregate Condition whose AggregateFunc is empty or set to a non-supported value (e.g. \"none\", \"sum\", \"every\") when constructed manually or copied from config.","commonSituations":"Mapping a custom formula DSL to formula.Condition and forgetting a translation for the aggregate verb; zero-value struct construction without setting AggregateFunc; renaming an aggregate function in downstream code without updating all writers.","solutions":["Set AggregateFunc to one of \"all\", \"any\", or \"count\" when building the Condition","Construct aggregates via formula.ParseCondition(\"children(x).all(status == 'complete')\") instead of struct literals","Whitelist-validate the function name before calling Evaluate"],"exampleFix":"// before\ncond := &formula.Condition{Type: formula.ConditionTypeAggregate, AggregateFunc: \"sum\", ...}\nres, err := cond.Evaluate(ctx) // unknown aggregate function: sum\n// after\ncond := &formula.Condition{Type: formula.ConditionTypeAggregate, AggregateFunc: \"count\", ...}\nres, err := cond.Evaluate(ctx)","handlingStrategy":"validation","validationCode":"func validAggFunc(f string) bool { return f == \"all\" || f == \"any\" || f == \"count\" }\nif cond.Type == formula.ConditionTypeAggregate && !validAggFunc(cond.AggregateFunc) {\n\treturn fmt.Errorf(\"aggregate func %q must be all|any|count\", cond.AggregateFunc)\n}","typeGuard":"func isKnownAggregateFunc(f string) bool {\n\treturn f == \"all\" || f == \"any\" || f == \"count\"\n}","tryCatchPattern":"res, err := cond.Evaluate(ctx)\nif err != nil && strings.HasPrefix(err.Error(), \"unknown aggregate function\") {\n\treturn fmt.Errorf(\"unsupported aggregate %q; allowed: all, any, count\", cond.AggregateFunc)\n}\nreturn res, err","preventionTips":["Map custom DSL aggregate verbs to exactly all/any/count","Never leave AggregateFunc zero-valued on aggregate conditions","Prefer ParseCondition(\"children(x).all(...)\") over manual struct assembly"],"tags":["formula","aggregate","condition-evaluation"],"backgroundTag":"invalid-enum-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}