gastownhall/beads · error

resolving formula %q: %w

Error message

resolving formula %q: %w

What it means

After loading, the helper resolves formula inheritance via `parser.Resolve` and wraps failures as `resolving formula %q`. Resolution walks `extends`/parent chains, merges steps and compose config, and fails on missing parents, inheritance cycles, or merge conflicts. The named formula loaded fine but its lineage is broken.

Source

Thrown at cmd/bd/cook.go:715

}

// resolveAndCookFormulaWithVars loads a formula and optionally filters steps by condition.
// If conditionVars is provided, steps with conditions that evaluate to false are excluded.
// Pass nil for conditionVars to include all steps (condition filtering skipped).
func resolveAndCookFormulaWithVars(formulaName string, searchPaths []string, conditionVars map[string]string) (*TemplateSubgraph, error) {
	// Create parser with search paths
	parser := formula.NewParser(searchPaths...)

	// Load formula by name
	f, err := parser.LoadByName(formulaName)
	if err != nil {
		return nil, fmt.Errorf("loading formula %q: %w", formulaName, err)
	}

	// Resolve inheritance
	resolved, err := parser.Resolve(f)
	if err != nil {
		return nil, fmt.Errorf("resolving formula %q: %w", formulaName, err)
	}

	// Validate any caller-provided variable values against enum/pattern/
	// required-empty constraints. This is deliberately presence-agnostic:
	// a var missing entirely is left to the caller's own UX (e.g. bd mol
	// pour/wisp's missing-var hint), but a var explicitly provided with a
	// value that violates its constraints must error here so it reaches
	// every caller of this shared path (pour, wisp, mol bond, mol seed) —
	// runCook does not go through this helper; it validates separately via
	// its own formula.ValidateVars call under --mode=runtime. Previously
	// only that `bd cook --mode=runtime` path enforced these (mybd-u2r6).
	if conditionVars != nil {
		if err := formula.ValidateProvidedVars(resolved, conditionVars); err != nil {
			return nil, fmt.Errorf("formula %q: %w", formulaName, err)
		}
	}

	// Apply control flow operators - loops, branches, gates

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped error to identify the failing parent in the `extends` chain and restore or fix it
  2. Check for inheritance cycles and break them by flattening the duplicated steps into the child
  3. Run `bd formula validate <name>` to validate the whole chain after edits
  4. Flatten the inheritance if the chain has grown fragile: copy the resolved content into a single standalone formula

Example fix

// before (child formula)
extends: base-deploy-v2   # renamed parent
// after
extends: base-deploy
Defensive patterns

Strategy: validation

Validate before calling

// walk extends chain for cycles and missing parents before resolve
seen := map[string]bool{}
for cur := f; cur != nil; {
    if seen[cur.Name] { return fmt.Errorf("inheritance cycle at %s", cur.Name) }
    seen[cur.Name] = true
    cur = loadParent(cur) // nil-stop on missing parent
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "cycle") {
        // flatten the extends chain
    }
    return fmt.Errorf("resolving formula %q: %w", name, err)
}

Prevention

When it happens

Trigger: A formula `extends` a parent that cannot be loaded; circular `extends` chains (A extends B extends A); invalid override keys during merge; parent formula has a type incompatible with the child.

Common situations: Refactoring formulas and renaming a parent without updating children; copy formulas across repos losing the parent file; hand-edited inheritance creating a cycle; deep chains where a grandparent was deleted.

Related errors


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