gastownhall/beads · error
read recipes.toml: %w
Error message
read recipes.toml: %w
What it means
LoadUserRecipes failed to read the user's recipes.toml from the .beads directory for a reason other than file-not-found (which is treated as 'no user recipes'). The underlying os.ReadFile error is wrapped for diagnostics.
Source
Thrown at internal/recipes/recipes.go:154
Description: "Junie guidelines and MCP configuration",
Paths: []string{".junie/guidelines.md", ".junie/mcp/mcp.json"},
},
}
// UserRecipes holds recipes loaded from user config file.
type UserRecipes struct {
Recipes map[string]Recipe `toml:"recipes"`
}
// LoadUserRecipes loads recipes from .beads/recipes.toml if it exists.
func LoadUserRecipes(beadsDir string) (map[string]Recipe, error) {
path := filepath.Join(beadsDir, "recipes.toml")
data, err := os.ReadFile(path) // #nosec G304 -- path is constructed from validated beadsDir
if os.IsNotExist(err) {
return nil, nil // No user recipes, that's fine
}
if err != nil {
return nil, fmt.Errorf("read recipes.toml: %w", err)
}
var userRecipes UserRecipes
if err := toml.Unmarshal(data, &userRecipes); err != nil {
return nil, fmt.Errorf("parse recipes.toml: %w", err)
}
// Set defaults for user recipes
for name, recipe := range userRecipes.Recipes {
if recipe.Type == "" {
recipe.Type = TypeFile
}
if recipe.Name == "" {
recipe.Name = name
}
userRecipes.Recipes[name] = recipe
}
View on GitHub (pinned to 71377f2769)
Solutions
- Check file permissions: `ls -l .beads/recipes.toml` and ensure the current user can read it (chmod 600/644)
- Verify the path is a regular file, not a directory: `file .beads/recipes.toml`
- Fix ownership if it was created by another user: `sudo chown $USER .beads/recipes.toml`
- If the file is unneeded/corrupt beyond repair, remove or rename it so loading proceeds with built-in recipes
Example fix
// before -rw------- root root .beads/recipes.toml // after chown $USER .beads/recipes.toml && chmod 600 .beads/recipes.toml
Defensive patterns
Strategy: try-catch
Validate before calling
info, err := os.Stat(filepath.Join(beadsDir, "recipes.toml"))
if err == nil && !info.Mode().IsRegular() {
return fmt.Errorf("recipes.toml is not a regular file")
}
if err == nil && info.Mode().Perm()&0o400 == 0 {
return fmt.Errorf("recipes.toml is not readable by current user")
} Try / catch
recipes, err := recipes.LoadUserRecipes(ctx, beadsDir)
if err != nil {
if os.IsPermission(errors.Unwrap(err)) {
// fall back to built-in recipes and warn
recipes = nil
} else {
return err
}
} Prevention
- Keep .beads files owned by the user running bd
- Avoid running bd with sudo (mixes file ownership)
- Do not replace recipes.toml with a directory or symlink
- Check permissions after restoring from backups (umask/ownership)
When it happens
Trigger: os.ReadFile on <beadsDir>/recipes.toml returns a non-IsNotExist error: permission denied, path is a directory, I/O error, or too many symlinks.
Common situations: recipes.toml exists but is unreadable due to restrictive file permissions, ownership issues after running as another user (root vs user), the path being a directory, or a failing disk/NFS mount.
Related errors
- dolt path is not executable
- failed to create backup directory: %w
- failed to create temp file: %w
- create beads directory: %w
- write metadata.json: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d8e2fe6dcba524e0.
Report an issue: GitHub.