{"record":{"id":"ab29ba0177eb3536","repo":"charmbracelet/crush","slug":"get-hour-day-heatmap-w","errorCode":null,"errorMessage":"get hour day heatmap: %w","messagePattern":"get hour day heatmap: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/stats.go","lineNumber":656,"sourceCode":"\n\t// Tool usage.\n\ttoolUsage, err := queries.GetToolUsage(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get tool usage: %w\", err)\n\t}\n\tfor _, t := range toolUsage {\n\t\tif name, ok := t.ToolName.(string); ok && name != \"\" {\n\t\t\tstats.ToolUsage = append(stats.ToolUsage, ToolUsage{\n\t\t\t\tToolName:  name,\n\t\t\t\tCallCount: t.CallCount,\n\t\t\t})\n\t\t}\n\t}\n\n\t// Hour/day heatmap.\n\theatmap, err := queries.GetHourDayHeatmap(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get hour day heatmap: %w\", err)\n\t}\n\tfor _, h := range heatmap {\n\t\tstats.HourDayHeatmap = append(stats.HourDayHeatmap, HourDayHeatmapPt{\n\t\t\tDayOfWeek:    int(h.DayOfWeek),\n\t\t\tHour:         int(h.Hour),\n\t\t\tSessionCount: h.SessionCount,\n\t\t})\n\t}\n\n\treturn stats, nil\n}\n\nfunc toInt64(v any) int64 {\n\tswitch val := v.(type) {\n\tcase int64:\n\t\treturn val\n\tcase float64:\n\t\treturn int64(val)","sourceCodeStart":638,"sourceCodeEnd":674,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/stats.go#L638-L674","documentation":"gatherStats wraps a failure from queries.GetHourDayHeatmap(ctx), the sqlc query that groups sessions by day-of-week and hour for the heatmap section of the stats report. The underlying database error is preserved via %w. Same failure family as the other stats queries in this function.","triggerScenarios":"Running `crush stats` when the heatmap aggregation query fails: locked/corrupt SQLite DB, unmigrated schema, I/O error while reading session rows.","commonSituations":"Concurrent crush session holding the SQLite write lock; corrupted history DB; older DB file missing tables the new query expects.","solutions":["Inspect the wrapped cause for the exact SQLite error (locked, corrupt, no such table).","Stop other crush processes that may lock the database and retry.","Let crush run migrations by starting it normally before using `crush stats`.","If the database is corrupt, restore a backup or delete/recreate the DB."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"stats, err := gatherStats(ctx, queries)\nif err != nil {\n    if errors.Is(err, sqlite.ErrLocked) || errors.Is(err, context.DeadlineExceeded) {\n        return retryWithBackoff(func() error { _, err := gatherStats(ctx, queries); return err })\n    }\n    return err\n}","preventionTips":["Close other crush sessions before generating large stats reports.","Apply DB migrations by running crush normally first.","Use a context with a sane timeout for stats queries.","Restore from backup if the DB shows corruption signs."],"tags":["database","sqlite","cli","stats"],"backgroundTag":"sqlite-database-error","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}