charmbracelet/crush · error

get usage by day: %w

Error message

get usage by day: %w

What it means

gatherStats fetches per-day usage aggregates via queries.GetUsageByDay and wraps any SQL failure with this message. It is the same SQLite failure family as the other gatherStats errors: the query either cannot execute against the DB or the DB is inaccessible.

Source

Thrown at internal/cmd/stats.go:563

	total, err := queries.GetTotalStats(ctx)
	if err != nil {
		return nil, fmt.Errorf("get total stats: %w", err)
	}
	stats.Total = TotalStats{
		TotalSessions:         total.TotalSessions,
		TotalPromptTokens:     toInt64(total.TotalPromptTokens),
		TotalCompletionTokens: toInt64(total.TotalCompletionTokens),
		TotalTokens:           toInt64(total.TotalPromptTokens) + toInt64(total.TotalCompletionTokens),
		TotalCost:             toFloat64(total.TotalCost),
		TotalMessages:         toInt64(total.TotalMessages),
		AvgTokensPerSession:   toFloat64(total.AvgTokensPerSession),
		AvgMessagesPerSession: toFloat64(total.AvgMessagesPerSession),
	}

	// Usage by day.
	dailyUsage, err := queries.GetUsageByDay(ctx)
	if err != nil {
		return nil, fmt.Errorf("get usage by day: %w", err)
	}
	for _, d := range dailyUsage {
		prompt := nullFloat64ToInt64(d.PromptTokens)
		completion := nullFloat64ToInt64(d.CompletionTokens)
		stats.UsageByDay = append(stats.UsageByDay, DailyUsage{
			Day:              fmt.Sprintf("%v", d.Day),
			PromptTokens:     prompt,
			CompletionTokens: completion,
			TotalTokens:      prompt + completion,
			Cost:             d.Cost.Float64,
			SessionCount:     d.SessionCount,
		})
	}

	// Usage by model.
	modelUsage, err := queries.GetUsageByModel(ctx)
	if err != nil {
		return nil, fmt.Errorf("get usage by model: %w", err)

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Retry after closing other crush sessions holding the DB
  2. Check DB integrity: `sqlite3 .crush/crush.db 'PRAGMA integrity_check;'`
  3. If the DB is corrupt, restore from backup or delete it to regenerate stats from scratch
  4. Ensure the crush version matches the DB schema version (upgrade/downgrade accordingly)

Example fix

// before
crush stats --data-dir /mnt/nfs/.crush  # locking errors
// after
crush stats --data-dir ~/.local/share/crush  # local fs, reliable SQLite locking
Defensive patterns

Strategy: retry

Validate before calling

db="${CRUSH_DATA_DIR:-.crush}/crush.db"
sqlite3 "$db" 'PRAGMA integrity_check;' | grep -q '^ok' && [ -r "$db" ] && echo "DB ready" || { echo "DB not ready" >&2; exit 1; }

Try / catch

stats, err := gatherStats(ctx, dbPath)
if err != nil && strings.Contains(err.Error(), "get usage by day") {
    // transient lock: retry once after backing off
    time.Sleep(time.Second)
    stats, err = gatherStats(ctx, dbPath)
}
if err != nil { return err }

Prevention

When it happens

Trigger: GetUsageByDay fails: locked/unreadable SQLite DB, missing or incompatible schema for the daily-aggregation query, or an I/O error reading the database while running `crush stats`.

Common situations: Corrupted crush.db after a crash; concurrent crush session holding the write lock; version mismatch between crush binary and an old database schema; --data-dir pointing to an empty/foreign directory.

Related errors


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