gastownhall/beads · error
read %s: %w
Error message
read %s: %w
What it means
ParseFile could not read the formula file from disk; os.ReadFile's error is wrapped as "read <path>: <reason>". This is the standard file-not-found / permission-denied family: the path resolved but the contents were unreadable.
Source
Thrown at internal/formula/parser.go:135
// ParseFile parses a formula from a file path.
// Detects format from extension: .formula.toml or .formula.json
func (p *Parser) ParseFile(path string) (*Formula, error) {
// Check cache first
absPath, err := filepath.Abs(path)
if err != nil {
return nil, fmt.Errorf("resolve path: %w", err)
}
if cached, ok := p.cache[absPath]; ok {
return cached, nil
}
// Read and parse the file
// #nosec G304 -- absPath comes from controlled search paths or explicit user input
data, err := os.ReadFile(absPath)
if err != nil {
return nil, fmt.Errorf("read %s: %w", path, err)
}
// Detect format from extension
var formula *Formula
if strings.HasSuffix(path, FormulaExtTOML) {
formula, err = p.ParseTOML(data)
} else {
formula, err = p.Parse(data)
}
if err != nil {
return nil, fmt.Errorf("parse %s: %w", path, err)
}
formula.Source = absPath
// Set source tracing info on all steps (gt-8tmz.18)
SetSourceInfo(formula)
View on GitHub (pinned to 71377f2769)
Solutions
- Confirm the file exists at the printed path (ls) and fix the path/casing if not.
- Check read permissions (chmod/chown) or re-clone the repository.
- If the formula should ship with the repo, commit it under .beads/formulas.
- Handle os.IsNotExist in callers to surface a friendly 'formula missing' message.
Example fix
// before
f, err := parser.ParseFile(".beads/formulas/scafolding.formula.toml") // not found
// after
f, err := parser.ParseFile(".beads/formulas/scaffolding.formula.toml") // correct name Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(path); err != nil {
return fmt.Errorf("formula file not available: %w", err)
} else if fi.IsDir() {
return fmt.Errorf("%s is a directory, not a formula file", path)
} Type guard
func readableFile(path string) bool {
fi, err := os.Stat(path)
return err == nil && !fi.IsDir()
} Try / catch
f, err := parser.ParseFile(path)
if err != nil {
var pe *fs.PathError
if errors.As(err, &pe) && os.IsNotExist(pe) {
return nil, fmt.Errorf("formula %s is not installed; commit it under .beads/formulas", path)
}
return nil, err
} Prevention
- Commit all formula files; verify with git status after cloning.
- Watch for filename casing differences across OS filesystems.
- Check read permissions after cloning as a different user.
When it happens
Trigger: Parser.ParseFile (via loadFormula) is given a path that does not exist, was deleted after discovery, lacks read permission, or is a directory.
Common situations: Formula file not committed/checked out; case-sensitive filesystem mismatch (Linux vs macOS filename casing); stale cache pointing at a removed temp file; file permissions after cloning as another user.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- identity: read proxy secret: %w
- dolt path is not executable
- server: NewDoltServer: failed to determine absolute path of
- server: NewDoltServer: failed to determine absolute path of
- server: NewDoltServer: failed to determine absolute path of
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/79be6c39d4423bcf.
Report an issue: GitHub.