gastownhall/beads · error

formula has no source path

Error message

formula has no source path

What it means

formulaToTOML in cmd/bd/formula.go converts a Formula back to TOML by re-reading the original JSON source file, because the parsed Formula struct loses ordering and formatting. If the Formula's Source field (path to the original JSON) is empty, the conversion cannot proceed and this error is thrown. It is reached from `bd formula convert` (runFormulaConvert) and bulk conversion (convertAllFormulas).

Source

Thrown at cmd/bd/formula.go:669

// findFormulaJSON searches for a JSON formula file by name.
func findFormulaJSON(name string) string {
	for _, dir := range getFormulaSearchPaths() {
		path := filepath.Join(dir, name+formula.FormulaExtJSON)
		if _, err := os.Stat(path); err == nil {
			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

View on GitHub (pinned to 71377f2769)

Solutions

  1. Load the formula from its JSON file via the normal loader so Source is populated before converting.
  2. Set f.Source to the original JSON file path before calling formulaToTOML.
  3. If the original JSON no longer exists, recreate/export the formula JSON first, then convert.
  4. For bulk conversion, ensure every formula in the directory has a recorded source path.

Example fix

// before
f := &formula.Formula{Name: "x"}
tomlBytes, err := formulaToTOML(f) // "formula has no source path"
// after
f.Source = ".beads/formulas/x.json"
tomlBytes, err := formulaToTOML(f)
Defensive patterns

Strategy: validation

Validate before calling

// before converting, ensure Source is set
if f.Source == "" {
    return fmt.Errorf("cannot convert formula %q: no source JSON path", f.Name)
}

Type guard

// Go
func convertible(f *formula.Formula) bool { return f != nil && f.Source != "" }

Prevention

When it happens

Trigger: Running formula conversion on a Formula instance whose Source field was never populated — e.g. a formula constructed in memory rather than loaded from a JSON file, or a formula loaded through a path that did not record its source.

Common situations: Programmatically built formulas passed to conversion; formulas loaded from an embedded or non-file store that don't set Source; older formula JSON files or loaders predating the Source field; converting a formula after the source file reference was cleared.

Related errors


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