{"record":{"id":"46fd5c2e30b146df","repo":"gastownhall/beads","slug":"unknown-field-s","errorCode":null,"errorMessage":"unknown field: %s","messagePattern":"unknown field: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/condition.go","lineNumber":268,"sourceCode":"\t}\n\n\tstep, ok := ctx.Steps[stepID]\n\tif !ok {\n\t\treturn &ConditionResult{\n\t\t\tSatisfied: false,\n\t\t\tReason:    fmt.Sprintf(\"step %q not found\", stepID),\n\t\t}, nil\n\t}\n\n\t// Get the field value\n\tvar actual interface{}\n\tif c.Field == \"status\" {\n\t\tactual = step.Status\n\t} else if strings.HasPrefix(c.Field, \"output.\") {\n\t\tpath := strings.TrimPrefix(c.Field, \"output.\")\n\t\tactual = getNestedValue(step.Output, path)\n\t} else {\n\t\treturn nil, fmt.Errorf(\"unknown field: %s\", c.Field)\n\t}\n\n\t// Compare\n\tsatisfied, reason := compare(actual, c.Operator, c.Value)\n\treturn &ConditionResult{\n\t\tSatisfied: satisfied,\n\t\tReason:    reason,\n\t}, nil\n}\n\nfunc (c *Condition) evaluateAggregate(ctx *ConditionContext) (*ConditionResult, error) {\n\t// Get the set of steps to aggregate over\n\tvar steps []*StepState\n\n\tswitch c.AggregateOver {\n\tcase \"children\":\n\t\tstepID := c.StepRef\n\t\tif stepID == \"step\" {","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/condition.go#L250-L286","documentation":"evaluateField only understands two field shapes on a step: the literal field \"status\" and any path starting with \"output.\". Any other field name in a field-type condition is rejected at evaluation time with this error.","triggerScenarios":"Evaluate() on a Condition of Type=field whose Field is neither \"status\" nor \"output.*\" — e.g. parsing `step.name == 'foo'` (fieldPattern accepts any dotted path) then evaluating it, or `review.title == 'x'`.","commonSituations":"Typos like `step.statuses`; using fields that exist on the underlying step object but are not exposed to the condition language (id, title, owner); assuming output fields are referenced without the `output.` prefix (`step.approved == true` instead of `step.output.approved == true`).","solutions":["Prefix step-output references with `output.`: use `step.output.approved == 'true'`, not `step.approved`","Only use the supported field `status` for step status checks: `step.status == 'complete'`","Pre-validate the field path before evaluating: accept only \"status\" or strings with the \"output.\" prefix"],"exampleFix":"// before\ncond, _ := formula.ParseCondition(\"step.approved == 'true'\")\nres, err := cond.Evaluate(ctx) // unknown field: approved\n// after\ncond, _ := formula.ParseCondition(\"step.output.approved == 'true'\")\nres, err := cond.Evaluate(ctx)","handlingStrategy":"validation","validationCode":"func validField(f string) bool { return f == \"status\" || strings.HasPrefix(f, \"output.\") }\nif !validField(cond.Field) {\n\treturn fmt.Errorf(\"field %q unsupported; use status or output.<path>\", cond.Field)\n}","typeGuard":"func isSupportedField(field string) bool {\n\treturn field == \"status\" || strings.HasPrefix(field, \"output.\")\n}","tryCatchPattern":"res, err := cond.Evaluate(ctx)\nif err != nil {\n\tvar msg string\n\tif _, scan := fmt.Sscanf(err.Error(), \"unknown field: %s\", &msg); scan == nil {\n\t\treturn fmt.Errorf(\"bad condition field %q: only 'status' and 'output.*' are allowed\", msg)\n\t}\n\treturn err\n}","preventionTips":["Reference step outputs as output.<path> (e.g. step.output.approved)","Reserve bare field names for status only","Lint condition strings for fields outside {status, output.*} before cooking the formula"],"tags":["formula","condition-evaluation","unsupported-field"],"backgroundTag":"unknown-condition-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}