gastownhall/beads · error

waits_for children-of() requires a step ID

Error message

waits_for children-of() requires a step ID

What it means

Formula validation supports waits_for values of the form children-of(step-id). This error is returned when the children-of(...) parentheses are empty — the syntax is recognized but no step ID was supplied, so the dependency is meaningless.

Source

Thrown at internal/formula/types.go:760

	return nil
}

// validateWaitsFor validates the waits_for field value.
// Valid formats:
//   - "all-children": wait for all dynamically-bonded children
//   - "any-children": wait for first child to complete
//   - "children-of(step-id)": wait for children of a specific step
func validateWaitsFor(value string, stepIDLocations map[string]string) error {
	// Simple gate types
	if value == "all-children" || value == "any-children" {
		return nil
	}

	// children-of(step-id) syntax
	if strings.HasPrefix(value, "children-of(") && strings.HasSuffix(value, ")") {
		stepID := value[len("children-of(") : len(value)-1]
		if stepID == "" {
			return fmt.Errorf("waits_for children-of() requires a step ID")
		}
		if _, exists := stepIDLocations[stepID]; !exists {
			return fmt.Errorf("waits_for references unknown step %q in children-of()", stepID)
		}
		return nil
	}

	return fmt.Errorf("waits_for has invalid value %q (must be all-children, any-children, or children-of(step-id))", value)
}

// validateChildDependsOn recursively validates depends_on and needs references for children.
func validateChildDependsOn(children []*Step, idLocations map[string]string, errs *[]string, prefix string) {
	for i, child := range children {
		childPrefix := fmt.Sprintf("%s.children[%d]", prefix, i)
		for _, dep := range child.DependsOn {
			if _, exists := idLocations[dep]; !exists {
				*errs = append(*errs, fmt.Sprintf("%s (%s): depends_on references unknown step %q", childPrefix, child.ID, dep))
			}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Put the target step ID inside the parentheses: waits_for = "children-of(setup)".
  2. If no dependency is needed, remove the waits_for entry entirely.
  3. Verify the referenced step ID exists elsewhere in the formula (otherwise the next check reports an unknown step).

Example fix

// before
waits_for = "children-of()"
// after
waits_for = "children-of(build)"
Defensive patterns

Strategy: validation

Validate before calling

for _, w := range step.WaitsFor {
    if strings.HasPrefix(w, "children-of(") && strings.TrimSuffix(strings.TrimPrefix(w, "children-of("), ")") == "" {
        return fmt.Errorf("step %s: empty children-of() dependency", step.ID)
    }
}

Try / catch

if verr := f.Validate(); verr != nil && strings.Contains(verr.Error(), "children-of() requires a step ID") { /* fix the waits_for entry */ }

Prevention

When it happens

Trigger: A step's waits_for field contains exactly "children-of()" (or "children-of( )") — the value passes the prefix/suffix check but the extracted stepID is empty.

Common situations: Authoring a formula and forgetting to fill in the step ID placeholder, or programmatic generation emitting an empty dependency list item.

Related errors


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