gastownhall/beads · error
unknown field: %s
Error message
unknown field: %s
What it means
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.
Source
Thrown at internal/formula/condition.go:268
}
step, ok := ctx.Steps[stepID]
if !ok {
return &ConditionResult{
Satisfied: false,
Reason: fmt.Sprintf("step %q not found", stepID),
}, nil
}
// Get the field value
var actual interface{}
if c.Field == "status" {
actual = step.Status
} else if strings.HasPrefix(c.Field, "output.") {
path := strings.TrimPrefix(c.Field, "output.")
actual = getNestedValue(step.Output, path)
} else {
return nil, fmt.Errorf("unknown field: %s", c.Field)
}
// Compare
satisfied, reason := compare(actual, c.Operator, c.Value)
return &ConditionResult{
Satisfied: satisfied,
Reason: reason,
}, nil
}
func (c *Condition) evaluateAggregate(ctx *ConditionContext) (*ConditionResult, error) {
// Get the set of steps to aggregate over
var steps []*StepState
switch c.AggregateOver {
case "children":
stepID := c.StepRef
if stepID == "step" {View on GitHub (pinned to 71377f2769)
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
Example fix
// before
cond, _ := formula.ParseCondition("step.approved == 'true'")
res, err := cond.Evaluate(ctx) // unknown field: approved
// after
cond, _ := formula.ParseCondition("step.output.approved == 'true'")
res, err := cond.Evaluate(ctx) Defensive patterns
Strategy: validation
Validate before calling
func validField(f string) bool { return f == "status" || strings.HasPrefix(f, "output.") }
if !validField(cond.Field) {
return fmt.Errorf("field %q unsupported; use status or output.<path>", cond.Field)
} Type guard
func isSupportedField(field string) bool {
return field == "status" || strings.HasPrefix(field, "output.")
} Try / catch
res, err := cond.Evaluate(ctx)
if err != nil {
var msg string
if _, scan := fmt.Sscanf(err.Error(), "unknown field: %s", &msg); scan == nil {
return fmt.Errorf("bad condition field %q: only 'status' and 'output.*' are allowed", msg)
}
return err
} Prevention
- 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
When it happens
Trigger: 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'`.
Common situations: 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`).
Related errors
- unknown condition type: %s
- unknown aggregate function: %s
- unknown external type: %s
- parsing formula: %w
- resolving formula: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/46fd5c2e30b146df.
Report an issue: GitHub.