gastownhall/beads · error

unknown recipe: %s

Error message

unknown recipe: %s

What it means

GetRecipe was asked for a recipe name that exists neither in the built-in recipes nor in the user's recipes.toml. There is no default/fuzzy matching — the exact name must exist.

Source

Thrown at internal/recipes/recipes.go:210

		result[name] = recipe
	}

	return result, nil
}

// GetRecipe looks up a recipe by name, checking user recipes first.
func GetRecipe(name string, beadsDir string) (*Recipe, error) {
	// Normalize name (lowercase, strip leading/trailing hyphens)
	name = strings.ToLower(strings.Trim(name, "-"))

	recipes, err := GetAllRecipes(beadsDir)
	if err != nil {
		return nil, err
	}

	recipe, ok := recipes[name]
	if !ok {
		return nil, fmt.Errorf("unknown recipe: %s", name)
	}

	return &recipe, nil
}

// SaveUserRecipe adds or updates a recipe in .beads/recipes.toml.
func SaveUserRecipe(beadsDir, name, path string) error {
	recipesPath := filepath.Join(beadsDir, "recipes.toml")

	// Load existing user recipes
	var userRecipes UserRecipes
	data, err := os.ReadFile(recipesPath) // #nosec G304 -- path is constructed from validated beadsDir
	if err == nil {
		if err := toml.Unmarshal(data, &userRecipes); err != nil {
			return fmt.Errorf("parse recipes.toml: %w", err)
		}
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("read recipes.toml: %w", err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. List available recipes (ListRecipeNames / the recipes list command) and use an exact existing name
  2. Check that .beads/recipes.toml actually defines the recipe under [recipes.<name>]
  3. Fix typos or case differences in the requested name
  4. If a recipe was renamed in an upgrade, update scripts/docs to the new name

Example fix

// before
recipe, err := recipes.GetRecipe(ctx, "setup-copilot")
// after
recipe, err := recipes.GetRecipe(ctx, "copilot")
Defensive patterns

Strategy: fallback

Validate before calling

names, err := recipes.ListRecipeNames(ctx, beadsDir)
if !slices.Contains(names, wanted) {
	return fmt.Errorf("recipe %q not found; available: %v", wanted, names)
}

Try / catch

r, err := GetRecipe(ctx, name)
if err != nil {
	if strings.HasPrefix(err.Error(), "unknown recipe") {
		// suggest closest match
		suggestClosest(name, knownNames)
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: Calling GetRecipe(name) (or the CLI command that uses it) with a name not present in the merged recipe map.

Common situations: Typos in the recipe name, a user recipe that failed to load (so only built-ins are visible), referencing a recipe deleted from recipes.toml, or following docs for a recipe renamed in a newer version.

Related errors


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