gastownhall/beads · error
read rules directory: %w
Error message
read rules directory: %w
What it means
RunAudit wraps os.ReadDir failures for the rules directory. A missing directory is deliberately NOT an error (returns empty AuditResult); this error fires only for other ReadDir failures such as permission denied or the path being a file.
Source
Thrown at cmd/bd/rules.go:578
var sourceNames []string
for _, r := range rules {
sourceNames = append(sourceNames, r.Name+".md")
}
sb.WriteString("\nSource rules: ")
sb.WriteString(strings.Join(sourceNames, ", "))
sb.WriteString("\n")
return sb.String(), nil
}
// RunAudit is the top-level orchestrator for `bd rules audit`.
func RunAudit(rulesDir string, threshold float64) (*AuditResult, error) {
entries, err := os.ReadDir(rulesDir)
if err != nil {
if os.IsNotExist(err) {
return &AuditResult{}, nil
}
return nil, fmt.Errorf("read rules directory: %w", err)
}
var rules []RuleFile
totalTokens := 0
for _, entry := range entries {
if entry.IsDir() {
continue
}
if !strings.HasSuffix(entry.Name(), ".md") {
continue
}
path := filepath.Join(rulesDir, entry.Name())
rf, err := ParseRuleFile(path)
if err != nil {
// Skip files that can't be parsed
fmt.Fprintf(os.Stderr, "Warning: skipping %s: %v\n", entry.Name(), err)View on GitHub (pinned to 71377f2769)
Solutions
- Check permissions: ls -ld <rulesDir>; ensure the running user has read+execute.
- Verify the path is a directory, not a file: test -d <rulesDir>.
- Fix ownership (chown/chmod) or point the rules dir config at a writable, readable location.
- If IsNotExist, no error is thrown — check that you are not confusing this with a different failure.
Example fix
// before
res, err := RunAudit(rulesDir, 0.5)
// after
if info, statErr := os.Stat(rulesDir); statErr == nil && !info.IsDir() {
return fmt.Errorf("rules path %s is not a directory", rulesDir)
}
res, err := RunAudit(rulesDir, 0.5) Defensive patterns
Strategy: validation
Validate before calling
if info, err := os.Stat(rulesDir); err != nil || !info.IsDir() {
return fmt.Errorf("rules dir %s is not a readable directory", rulesDir)
} Try / catch
res, err := RunAudit(rulesDir, threshold)
if err != nil {
return fmt.Errorf("rules audit failed: %w", err) // check permissions first
} Prevention
- Ensure the rules dir is a directory, not a file.
- chmod/chown the rules dir so the bd process user can read it.
- Note that a missing dir returns an empty result, not this error — distinguish cases when debugging.
When it happens
Trigger: RunAudit called with a rulesDir that exists but is unreadable (permissions) or is a regular file rather than a directory.
Common situations: Rules directory with restrictive permissions (e.g. created by another user or root-only); config pointing rulesDir at a file; mounted volume with wrong ownership; containerized environments with dropped capabilities.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- failed to open file: %w
- read rule file %s: %w
- failed to read config.yaml: %w
- reading config: %w
- reading last_pull: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/6bf0b791f8e69953.
Report an issue: GitHub.