gastownhall/beads · error

reading source: %w

Error message

reading source: %w

What it means

formulaToTOML reads the formula's original JSON file at f.Source with os.ReadFile before converting it to TOML. If that read fails — the file doesn't exist, the path is wrong, or permissions deny access — the error is wrapped as 'reading source: %w'. The underlying cause is preserved via %w for inspection with errors.Is/As (e.g. os.ErrNotExist).

Source

Thrown at cmd/bd/formula.go:675

			return path
		}
	}
	return ""
}

// formulaToTOML converts a Formula to TOML bytes.
// Uses a custom structure optimized for TOML readability.
func formulaToTOML(f *formula.Formula) ([]byte, error) {
	// We need to re-read the original JSON to get the raw structure
	// because the Formula struct loses some ordering/formatting
	if f.Source == "" {
		return nil, fmt.Errorf("formula has no source path")
	}

	// Read the original JSON
	jsonData, err := os.ReadFile(f.Source)
	if err != nil {
		return nil, fmt.Errorf("reading source: %w", err)
	}

	// Parse into a map to preserve structure
	var raw map[string]interface{}
	if err := json.Unmarshal(jsonData, &raw); err != nil {
		return nil, fmt.Errorf("parsing JSON: %w", err)
	}

	// Fix float64 to int for known integer fields
	fixIntegerFields(raw)

	// Encode to TOML
	var buf bytes.Buffer
	encoder := toml.NewEncoder(&buf)
	encoder.Indent = ""
	if err := encoder.Encode(raw); err != nil {
		return nil, fmt.Errorf("encoding TOML: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the source JSON exists at f.Source (ls the path); restore or regenerate it if missing.
  2. Run the command from the correct working directory if Source is a relative path.
  3. Fix file permissions (chmod/chown) so the process can read the file.
  4. Inspect the wrapped cause: errors.Is(err, os.ErrNotExist) vs permission errors to choose the fix.

Example fix

// before
f.Source = "formulas/deploy.json" // relative, cwd changed
// after
f.Source = "/abs/path/to/.beads/formulas/deploy.json" // resolve relative to repo root
Defensive patterns

Strategy: validation

Validate before calling

// before conversion
if _, err := os.Stat(f.Source); err != nil {
    return fmt.Errorf("formula source missing: %w", err)
}

Try / catch

if _, err := formulaToTOML(f); err != nil {
    if errors.Is(err, os.ErrNotExist) { /* regenerate or restore source JSON */ }
    if errors.Is(err, os.ErrPermission) { /* fix permissions */ }
}

Prevention

When it happens

Trigger: Running `bd formula convert` (or convertAllFormulas) where the recorded Source path no longer exists, was moved/renamed, or is unreadable due to file permissions.

Common situations: Source file deleted or moved after the formula was loaded; working directory changed so a relative path no longer resolves; permission changes after checkout or in CI containers running as a different user; formula JSON generated in a temp dir that was cleaned up.

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


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