charmbracelet/crush · error

failed to connect to database: %w

Error message

failed to connect to database: %w

What it means

runStats wraps any error from db.Connect, which opens (or fetches from a pool) the SQLite database at <dataDir>/crush.db, pings it, and applies migrations. This error means the database could not be opened or pinged: the data directory could not be created, the data-dir lock could not be acquired (another crush process holds it), the SQLite file is corrupt/unreadable, or the ping failed (bad driver state, cancelled context, file locked).

Source

Thrown at internal/cmd/stats.go:174

			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 {
			return fmt.Errorf("failed to gather stats: %w", err)
		}

		projectStats = []ProjectStats{{ProjectPath: "", Stats: stats}}
	}

	if len(projectStats) == 0 {
		return fmt.Errorf("no data available: no projects found")
	}

	// Merge stats from all projects.
	mergedStats := mergeStats(projectStats)

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check no other crush process is running against the same data dir (lock contention) and that <dataDir> is writable: ls -ld "$HOME/.local/share/crush".
  2. Inspect crush.db integrity with `sqlite3 crush.db 'PRAGMA integrity_check;'`; restore from backup or remove corrupted crush.db (and -wal/-shm) if acceptable.
  3. Verify env vars controlling the data dir (XDG_DATA_HOME, HOME) point to a writable directory; unset overrides or fix the path.
  4. If migrations or lock logs appear in stderr, read the wrapped %w cause shown by the error and address it specifically.
  5. Re-run the command; transient ping/IO failures (network home dirs, EFS/NFS) may resolve on retry.

Example fix

// before
conn, err := db.Connect(ctx, dataDir)
if err != nil {
	return fmt.Errorf("failed to connect to database: %w", err)
}
// after
if dataDir == "" {
	dataDir = defaultDataDir() // fall back to the standard data dir
}
conn, err := db.Connect(ctx, dataDir)
if err != nil {
	var lockErr *db.DataDirLockError
	if errors.As(err, &lockErr) {
		return fmt.Errorf("another crush process is using %s; close it and retry", dataDir)
	}
	return fmt.Errorf("failed to connect to database: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

if info, err := os.Stat(filepath.Join(dataDir, "crush.db")); err == nil && info.Size() == 0 {
	return fmt.Errorf("database file %s is empty/corrupt", dataDir)
}
if err := unix.Flock(lockFile, unix.LOCK_EX|unix.LOCK_NB); err != nil {
	return fmt.Errorf("another crush instance holds the data dir")
}

Try / catch

conn, err := db.Connect(ctx, dataDir)
if err != nil {
	var lockErr *fs.PathError
	if errors.As(err, &lockErr) {
		return fmt.Errorf("data dir unusable (%s): %w", dataDir, err)
	}
	return err
}

Prevention

When it happens

Trigger: Running `crush stats` where: (1) the data dir path is invalid or permissions deny os.MkdirAll; (2) another crush process holds the data-dir lock (WithDataDirLock); (3) crush.db is corrupted (e.g. SQLITE_NOTADB from prior WAL desync) or truncated; (4) the context is cancelled or the filesystem disallows opening/writing crush.db; (5) dataDir resolved to empty (db.Connect returns "data.dir is not set").

Common situations: Running stats while another crush instance is open on the same data dir; running with XDG_DATA_HOME/CRUSH_DATA pointed at a read-only or nonexistent mount; copying a crush.db without its -wal/-shm files causing SQLITE_NOTADB; disk full; running in a sandbox with restricted HOME.

Related errors


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