gastownhall/beads · error

%q is not an aspect formula (type=%s)

Error message

%q is not an aspect formula (type=%s)

What it means

`bd cook` validates that every formula named in `compose.aspects` actually has `type: aspect`. If the loaded formula's `Type` differs from `formula.TypeAspect`, cook refuses to apply its advice and reports the actual type. This guards against composing with a step-procedure or other non-aspect formula whose advice semantics don't apply.

Source

Thrown at cmd/bd/cook.go:209

	// Apply expansion operators
	if resolved.Compose != nil && (len(resolved.Compose.Expand) > 0 || len(resolved.Compose.Map) > 0) {
		expandedSteps, err := formula.ApplyExpansions(resolved.Steps, resolved.Compose, parser)
		if err != nil {
			return nil, fmt.Errorf("applying expansions: %w", err)
		}
		resolved.Steps = expandedSteps
	}

	// Apply aspects from compose.aspects
	if resolved.Compose != nil && len(resolved.Compose.Aspects) > 0 {
		for _, aspectName := range resolved.Compose.Aspects {
			aspectFormula, err := parser.LoadByName(aspectName)
			if err != nil {
				return nil, fmt.Errorf("loading aspect %q: %w", aspectName, err)
			}
			if aspectFormula.Type != formula.TypeAspect {
				return nil, fmt.Errorf("%q is not an aspect formula (type=%s)", aspectName, aspectFormula.Type)
			}
			if len(aspectFormula.Advice) > 0 {
				resolved.Steps = formula.ApplyAdvice(resolved.Steps, aspectFormula.Advice)
			}
		}
	}

	return resolved, nil
}

// outputCookDryRun displays a dry-run preview of what would be cooked
func outputCookDryRun(resolved *formula.Formula, protoID string, runtimeMode bool, inputVars map[string]string, vars, bondPoints []string) {
	modeLabel := "compile-time"
	if runtimeMode {
		modeLabel = "runtime"
		// Apply defaults for runtime mode display
		for name, def := range resolved.Vars {
			if _, provided := inputVars[name]; !provided && def.Default != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Open the aspect formula file and set `type: aspect` in its front matter
  2. If the referenced formula is not meant to be an aspect, remove it from `compose.aspects` and reference the correct aspect name
  3. Run `bd formula validate <name>` (or equivalent) to confirm the type is recognized after editing

Example fix

// before (aspect formula front matter)
type: procedure
// after
type: aspect
Defensive patterns

Strategy: validation

Validate before calling

f, err := parser.LoadByName(name)
if err != nil { return err }
if f.Type != formula.TypeAspect {
    return fmt.Errorf("%q has type %s, need aspect", name, f.Type)
}

Type guard

func isAspect(f *formula.Formula) bool { return f != nil && f.Type == formula.TypeAspect }

Prevention

When it happens

Trigger: `compose.aspects` references a formula whose front-matter declares a different type (e.g. `type: procedure`, `type: pipeline`). Loading succeeds, but the type check at cook.go:209 fails.

Common situations: Authoring a new formula and forgetting `type: aspect` in its front matter; pointing `compose.aspects` at a main formula by mistake; copying an aspect but leaving the parent's type value; old formulas written before the type field existed.

Related errors


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