charmbracelet/crush · error

failed to generate HTML: %w

Error message

failed to generate HTML: %w

What it means

`crush stats` renders the gathered statistics into an HTML report at <dataDir>/stats/index.html. This error wraps any failure inside generateHTML (template execution or file creation/write). The wrapped error tells whether it was a template rendering issue or an I/O problem.

Source

Thrown at internal/cmd/stats.go:230

			return fmt.Errorf("failed to get current directory: %w", err)
		}
		projName = strings.Replace(project, currentUser.HomeDir, "~", 1)
	}

	outputDataDir := dataDir
	if outputDataDir == "" {
		cfg, err := config.Init("", "", false)
		if err == nil {
			outputDataDir = cfg.Config().Options.DataDirectory
		}
	}
	if outputDataDir == "" {
		outputDataDir = ".crush"
	}

	htmlPath := filepath.Join(outputDataDir, "stats/index.html")
	if err := generateHTML(mergedStats, projectStats, projName, username, htmlPath); err != nil {
		return fmt.Errorf("failed to generate HTML: %w", err)
	}

	fmt.Printf("Stats generated: %s\n", htmlPath)

	if err := browser.OpenFile(htmlPath); err != nil {
		fmt.Printf("Could not open browser: %v\n", err)
		fmt.Println("Please open the file manually.")
	}

	return nil
}

// crawlForStats crawls a directory recursively looking for .crush/crush.db files.
func crawlForStats(ctx context.Context, rootDir string) ([]ProjectStats, error) {
	var dbPaths []struct {
		dbPath     string
		projectDir string
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check that the data dir (default .crush) is writable: `ls -ld .crush` and fix permissions
  2. Verify free disk space with `df -h`
  3. If using a custom --data-dir, ensure the path exists or can be created and is writable
  4. Run `crush stats` from a directory where you own .crush (fix ownership with chown)

Example fix

// before
mkdir /protected && crush stats --data-dir /protected/out  # permission denied
// after
mkdir -p ~/crush-stats && crush stats --data-dir ~/crush-stats
Defensive patterns

Strategy: try-catch

Validate before calling

datadir="${CRUSH_DATA_DIR:-.crush}"
if [ ! -w "$datadir" ]; then
  echo "Data dir $datadir is not writable" >&2
  exit 1
fi
if [ "$(df -h . | awk 'NR==2{print $5}' | tr -d '%')" -ge 99 ]; then
  echo "Disk full; free space before generating stats" >&2
  exit 1
fi

Try / catch

if err := runStats(...); err != nil {
    if errors.Is(err, os.ErrPermission) {
        fmt.Fprintln(os.Stderr, "Fix permissions on the stats data dir and retry")
        return nil
    }
    return err // includes template-execution errors via %w
}

Prevention

When it happens

Trigger: generateHTML fails to create or write the output file (bad permissions, read-only filesystem, <dataDir>/stats not creatable) or fails while executing the HTML template against mergedStats/projectStats.

Common situations: .crush directory on a read-only mount or owned by another user; disk full; data dir overridden via --data-dir to a path without write permission; corrupted/nil stats triggering template nil-pointer issues.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/b3374654fa92de6d. Report an issue: GitHub.