{"record":{"id":"d8e2fe6dcba524e0","repo":"gastownhall/beads","slug":"read-recipes-toml-w","errorCode":null,"errorMessage":"read recipes.toml: %w","messagePattern":"read recipes\\.toml: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/recipes/recipes.go","lineNumber":154,"sourceCode":"\t\tDescription: \"Junie guidelines and MCP configuration\",\n\t\tPaths:       []string{\".junie/guidelines.md\", \".junie/mcp/mcp.json\"},\n\t},\n}\n\n// UserRecipes holds recipes loaded from user config file.\ntype UserRecipes struct {\n\tRecipes map[string]Recipe `toml:\"recipes\"`\n}\n\n// LoadUserRecipes loads recipes from .beads/recipes.toml if it exists.\nfunc LoadUserRecipes(beadsDir string) (map[string]Recipe, error) {\n\tpath := filepath.Join(beadsDir, \"recipes.toml\")\n\tdata, err := os.ReadFile(path) // #nosec G304 -- path is constructed from validated beadsDir\n\tif os.IsNotExist(err) {\n\t\treturn nil, nil // No user recipes, that's fine\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read recipes.toml: %w\", err)\n\t}\n\n\tvar userRecipes UserRecipes\n\tif err := toml.Unmarshal(data, &userRecipes); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse recipes.toml: %w\", err)\n\t}\n\n\t// Set defaults for user recipes\n\tfor name, recipe := range userRecipes.Recipes {\n\t\tif recipe.Type == \"\" {\n\t\t\trecipe.Type = TypeFile\n\t\t}\n\t\tif recipe.Name == \"\" {\n\t\t\trecipe.Name = name\n\t\t}\n\t\tuserRecipes.Recipes[name] = recipe\n\t}\n","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/recipes/recipes.go#L136-L172","documentation":"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.","triggerScenarios":"os.ReadFile on <beadsDir>/recipes.toml returns a non-IsNotExist error: permission denied, path is a directory, I/O error, or too many symlinks.","commonSituations":"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.","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"],"exampleFix":"// before\n-rw------- root root .beads/recipes.toml\n// after\nchown $USER .beads/recipes.toml && chmod 600 .beads/recipes.toml","handlingStrategy":"try-catch","validationCode":"info, err := os.Stat(filepath.Join(beadsDir, \"recipes.toml\"))\nif err == nil && !info.Mode().IsRegular() {\n\treturn fmt.Errorf(\"recipes.toml is not a regular file\")\n}\nif err == nil && info.Mode().Perm()&0o400 == 0 {\n\treturn fmt.Errorf(\"recipes.toml is not readable by current user\")\n}","typeGuard":null,"tryCatchPattern":"recipes, err := recipes.LoadUserRecipes(ctx, beadsDir)\nif err != nil {\n\tif os.IsPermission(errors.Unwrap(err)) {\n\t\t// fall back to built-in recipes and warn\n\t\trecipes = nil\n\t} else {\n\t\treturn err\n\t}\n}","preventionTips":["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)"],"tags":["filesystem","permissions","toml"],"backgroundTag":"file-read-permission-denied","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}