gastownhall/beads · error
formula %q not found in search paths
Error message
formula %q not found in search paths
What it means
loadFormula() searched every configured search path for a formula file matching the requested name and found nothing (os.Stat failed for each candidate path). It is the library's canonical 'no such formula' error, exposed publicly through LoadByName for expansion operators.
Source
Thrown at internal/formula/parser.go:303
// Tries TOML first (.formula.toml), then falls back to JSON (.formula.json).
func (p *Parser) loadFormula(name string) (*Formula, error) {
// Check cache first
if cached, ok := p.cache[name]; ok {
return cached, nil
}
// Search for the formula file - try TOML first, then JSON
extensions := []string{FormulaExtTOML, FormulaExtJSON}
for _, dir := range p.searchPaths {
for _, ext := range extensions {
path := filepath.Join(dir, name+ext)
if _, err := os.Stat(path); err == nil {
return p.ParseFile(path)
}
}
}
return nil, fmt.Errorf("formula %q not found in search paths", name)
}
// LoadByName loads a formula by name from search paths.
// This is the public API for loading formulas used by expansion operators.
func (p *Parser) LoadByName(name string) (*Formula, error) {
return p.loadFormula(name)
}
// mergeSteps merges child steps into parent steps.
// Child steps with the same ID as a parent step replace the parent step
// in-place (preserving position). Child steps with new IDs are appended.
func mergeSteps(parent, child []*Step) []*Step {
// Index parent steps by ID for quick lookup
parentIdx := make(map[string]int, len(parent))
for i, s := range parent {
parentIdx[s.ID] = i
}
View on GitHub (pinned to 71377f2769)
Solutions
- Verify the formula file exists and its name matches exactly (case-sensitive) what you passed to LoadByName or put in extends.
- Add the formula's directory to the parser's search paths when constructing the Parser.
- List the search-path directories and the formulas in them to confirm the expected file is present and named per convention.
Example fix
// before
p := NewParser(WithSearchPaths("./formulas"))
f, err := p.LoadByName("deploy") // file is in ./molecules/deploy.md
// after
p := NewParser(WithSearchPaths("./formulas", "./molecules"))
f, err := p.LoadByName("deploy") Defensive patterns
Strategy: validation
Validate before calling
// Verify the formula file exists in a search path before LoadByName.
func formulaExists(name string, searchPaths []string) bool {
for _, dir := range searchPaths {
if _, err := os.Stat(filepath.Join(dir, name+".md")); err == nil {
return true
}
}
return false
} Try / catch
f, err := p.LoadByName(name)
if err != nil {
if strings.Contains(err.Error(), "not found in search paths") {
// suggest closest matches by listing the search dirs
}
} Prevention
- Configure all formula directories in WithSearchPaths up front.
- Match names exactly (case-sensitive) to filenames; avoid ad-hoc renaming.
- Provide a 'list formulas' command built on the same search paths so users can see valid names.
When it happens
Trigger: Parser.LoadByName("name") with no matching formula file in the search paths; Resolve on a formula whose extends entry names a nonexistent parent (then wrapped by 1741); expansion operators resolving a formula reference that does not exist.
Common situations: Typos in the formula name; formula file never created; file lives outside the configured search paths; wrong file extension or naming convention so the Stat candidate paths never match; working from a different repo checkout where the formula directory is absent.
Related errors
- inline expand on step %q: loading %q: %w
- parsing formula: %w
- loading aspect %q: %w
- loading formula %q: %w
- reading source: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/32a2607ab50a9941.
Report an issue: GitHub.