charmbracelet/crush · error

failed to initialize config: %w

Error message

failed to initialize config: %w

What it means

In the default mode (no --crawl-dir / --all), `crush stats` first loads configuration via `config.Init("", dataDir, false)`. This error wraps any config-initialization failure — invalid or unreadable crush config files, malformed JSON/crushrc, or failures resolving the data directory — as `failed to initialize config: <cause>`. The root cause is always in the wrapped `%w` chain.

Source

Thrown at internal/cmd/stats.go:161

	var projectStats []ProjectStats
	var err error

	switch {
	case crawlDir != "":
		projectStats, err = crawlForStats(ctx, crawlDir)
		if err != nil {
			return fmt.Errorf("failed to crawl for stats: %w", err)
		}
	case useAll:
		projectStats, err = gatherStatsFromProjects(ctx)
		if err != nil {
			return fmt.Errorf("failed to gather stats from projects: %w", err)
		}
	default:
		cfg, err := config.Init("", dataDir, false)
		if err != nil {
			return fmt.Errorf("failed to initialize config: %w", err)
		}
		if dataDir == "" {
			dataDir = cfg.Config().Options.DataDirectory
		}
		if shouldEnableMetrics(cfg.Config()) {
			event.Init()
		}

		event.StatsViewed()

		conn, err := db.Connect(ctx, dataDir)
		if err != nil {
			return fmt.Errorf("failed to connect to database: %w", err)
		}
		defer conn.Close()

		stats, err := gatherStats(ctx, conn)
		if err != nil {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Read the wrapped cause after the colon — it names the offending config file and usually the parse problem (line/column).
  2. Validate the JSON config: `jq . crush.json` (or fix syntax errors in your .crushrc script).
  3. Check file permissions on crush.json / .crushrc in the cwd, parent dirs, and the global config location.
  4. If you passed --data-dir, verify it is a valid writable directory path.
  5. Temporarily rename suspect config files (crush.json, .crushrc) and re-run to confirm which one breaks init.

Example fix

// before
crush stats --data-dir /etc/passwd
# failed to initialize config: ...
// after
mkdir -p ~/.local/share/crush-data
crush stats --data-dir ~/.local/share/crush-data
Defensive patterns

Strategy: validation

Validate before calling

// Validate config files before running crush stats
for _, f := range []string{"crush.json", ".crushrc"} {
    if _, err := os.Stat(f); err == nil {
        if strings.HasSuffix(f, ".json") {
            data, err := os.ReadFile(f)
            if err != nil {
                log.Fatalf("config %s unreadable: %v", f, err)
            }
            var v any
            if err := json.Unmarshal(data, &v); err != nil {
                log.Fatalf("config %s is invalid JSON: %v", f, err)
            }
        }
    }
}

Type guard

func isReadableFile(path string) bool {
    f, err := os.Open(path)
    if err != nil {
        return false
    }
    f.Close()
    return true
}

Try / catch

out, err := exec.Command("crush", "stats").CombinedOutput()
if err != nil {
    if strings.Contains(string(out), "failed to initialize config") {
        log.Fatalf("fix your crush config first: %s", out)
    }
    log.Fatalf("stats failed: %v: %s", err, out)
}

Prevention

When it happens

Trigger: Running plain `crush stats` where `config.Init("", dataDir, false)` at internal/cmd/stats.go:159 returns an error: a malformed crush.json / .crushrc in the working or parent directories, unreadable global config, or an invalid --data-dir value.

Common situations: Hand-edited crush.json with invalid JSON; a crushrc script with a failing builtin or syntax error; config file owned by root/unreadable; invalid --data-dir flag (e.g. path exists as a file); schema changes after upgrading crush with an old config field.

Related errors


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