{"record":{"id":"9c1988812ae6a13a","repo":"charmbracelet/crush","slug":"failed-to-load-projects-w","errorCode":null,"errorMessage":"failed to load projects: %w","messagePattern":"failed to load projects: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/stats.go","lineNumber":317,"sourceCode":"\t\t\"logs\":             true,\n\t\t\"generated\":        true,\n\t\t\"bower_components\": true,\n\t\t\"jspm_packages\":    true,\n\t\t\".cache\":           true,\n\t\t\".npm\":             true,\n\t\t\".cargo\":           true,\n\t\t\"Library\":          true,\n\t\t\"Applications\":     true,\n\t\t\"System\":           true,\n\t}\n\treturn skipDirs[name]\n}\n\n// gatherStatsFromProjects gathers stats from all known projects in projects.json.\nfunc gatherStatsFromProjects(ctx context.Context) ([]ProjectStats, error) {\n\tprojectList, err := projects.Load()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load projects: %w\", err)\n\t}\n\n\tvar dbPaths []struct {\n\t\tdbPath     string\n\t\tprojectDir string\n\t}\n\n\tfor _, p := range projectList.Projects {\n\t\tdbPath := filepath.Join(p.DataDir, \"crush.db\")\n\t\tif _, err := os.Stat(dbPath); err == nil {\n\t\t\tdbPaths = append(dbPaths, struct {\n\t\t\t\tdbPath     string\n\t\t\t\tprojectDir string\n\t\t\t}{dbPath: dbPath, projectDir: p.Path})\n\t\t}\n\t}\n\n\treturn gatherStatsFromDBPaths(ctx, dbPaths)","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/stats.go#L299-L335","documentation":"When `crush stats --all` is used, stats are gathered from every project listed in projects.json (next to the global config). This error wraps a failure from projects.Load(), which can only happen if projects.json exists but is unreadable or is not valid JSON.","triggerScenarios":"Running `crush stats` with the all-projects flag when projects.json cannot be read (permission denied) or json.Unmarshal fails because the file is malformed/hand-edited incorrectly.","commonSituations":"Manually editing ~/.config/crush/projects.json and breaking the JSON syntax; file owned by root after running crush with sudo once; disk corruption; truncation from an interrupted write.","solutions":["Validate the file: `cat $(dirname $(crush config path))/projects.json | jq .` — fix or remove broken JSON","If the file is corrupt and not needed, delete it; projects.Load() recreates an empty list when it is absent","Fix permissions on the file so the current user can read it (chown/chmod)"],"exampleFix":"// before (corrupt projects.json)\n{\"projects\": [ {\"path\": \"/a\",  // truncated\n// after\nrm projects.json  # or repair with jq; Load() then returns an empty project list","handlingStrategy":"validation","validationCode":"pj=\"$(dirname \"$(crush config path 2>/dev/null)\")/projects.json\"\nif [ -f \"$pj\" ] && ! jq empty \"$pj\" 2>/dev/null; then\n  echo \"projects.json is invalid JSON; repair or remove it: $pj\" >&2\n  exit 1\nfi","typeGuard":null,"tryCatchPattern":"if err := runStats(...); err != nil {\n    var syntaxErr *json.SyntaxError\n    if errors.As(err, &syntaxErr) {\n        fmt.Fprintf(os.Stderr, \"projects.json corrupt at offset %d; delete it to reset\\n\", syntaxErr.Offset)\n        return nil\n    }\n    return err\n}","preventionTips":["Never hand-edit projects.json without validating with jq afterwards","Avoid running crush with sudo, which can leave unreadable root-owned config files","Back up the config directory before modifying it","If stats --all fails on load, deleting projects.json is safe: Load returns an empty list when the file is missing"],"tags":["json","filesystem","config","cli"],"backgroundTag":"json-parse-error","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}