{"record":{"id":"a107e3f6fed3d746","repo":"gastownhall/beads","slug":"map-q-is-not-an-expansion-formula-type-s","errorCode":null,"errorMessage":"map: %q is not an expansion formula (type=%s)","messagePattern":"map: %q is not an expansion formula \\(type=(.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/expand.go","lineNumber":113,"sourceCode":"\t\tif len(expandedSteps) > 0 {\n\t\t\tlastStepID := expandedSteps[len(expandedSteps)-1].ID\n\t\t\tresult = UpdateDependenciesForExpansion(result, rule.Target, lastStepID)\n\t\t}\n\n\t\t// Rebuild stepMap from result so subsequent iterations see resolved deps\n\t\tstepMap = buildStepMap(result)\n\t}\n\n\t// Apply map rules (pattern matching)\n\tfor _, rule := range compose.Map {\n\t\t// Load the expansion formula\n\t\texpFormula, err := parser.LoadByName(rule.With)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"map: loading %q: %w\", rule.With, err)\n\t\t}\n\n\t\tif expFormula.Type != TypeExpansion {\n\t\t\treturn nil, fmt.Errorf(\"map: %q is not an expansion formula (type=%s)\", rule.With, expFormula.Type)\n\t\t}\n\n\t\tif len(expFormula.Template) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"map: %q has no template steps\", rule.With)\n\t\t}\n\n\t\t// Merge formula default vars with rule overrides\n\t\tvars := mergeVars(expFormula, rule.Vars)\n\n\t\t// Find all matching steps (including nested children)\n\t\t// Rebuild stepMap to capture any changes from previous expansions\n\t\tstepMap = buildStepMap(result)\n\t\tvar toExpand []*Step\n\t\tfor id, step := range stepMap {\n\t\t\tif MatchGlob(rule.Select, id) && !expanded[id] {\n\t\t\t\ttoExpand = append(toExpand, step)\n\t\t\t}\n\t\t}","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/expand.go#L95-L131","documentation":"Same check as the expand-rule variant but for map rules: the formula loaded by a map rule's `with:` is not of type expansion. Map rules require expansion formulas because they substitute each matching step into a template.","triggerScenarios":"ApplyExpansions loads a map rule's `with:` formula successfully, but expFormula.Type is workflow/aspect/convoy instead of TypeExpansion.","commonSituations":"Pointing a map rule at a workflow formula by mistake; a formula's type was changed after the compose referenced it; copying a `with:` value from another compose section.","solutions":["Set the referenced formula's type to `expansion`","Update the map rule's `with:` to name an actual expansion formula","Remove the map rule if expansion is not intended"],"exampleFix":"# before\nwith: deploy-aspect   # type: aspect\n# after\nwith: deploy-expand   # type: expansion","handlingStrategy":"validation","validationCode":"f, err := parser.LoadByName(rule.With)\nif err == nil && f.Type != formula.TypeExpansion {\n    return fmt.Errorf(\"map rule with=%q must reference an expansion formula, got %s\", rule.With, f.Type)\n}","typeGuard":"func isExpansion(f *formula.Formula) bool { return f != nil && f.Type == formula.TypeExpansion }","tryCatchPattern":"expanded, err := formula.ApplyExpansions(steps, compose)\nif err != nil && strings.Contains(err.Error(), \"is not an expansion formula\") {\n    return fmt.Errorf(\"map rule points at wrong formula type: %w\", err)\n}","preventionTips":["Only reference *-expand formulas from map rules","Validate formula types for all compose references in CI","Avoid retyping existing formulas; create a new expansion formula instead"],"tags":["formula","map","config"],"backgroundTag":"wrong-formula-type","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}