{"record":{"id":"b88c6717aa8430d8","repo":"JuliusBrussee/caveman","slug":"encode-stats-report-w","errorCode":null,"errorMessage":"encode stats report: %w","messagePattern":"encode stats report: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/stats_report.go","lineNumber":23,"sourceCode":"\t\"fmt\"\n\t\"html/template\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc DefaultStatsReportPath(home string) string {\n\treturn filepath.Join(home, \"reports\", \"caveman-stats.html\")\n}\n\n// WriteStatsHTML writes a private, self-contained snapshot. The page only rolls\n// up recorded metric groups; it never derives a price or upgrades evidence.\nfunc (s *Store) WriteStatsHTML(report StatsReport, outPath string) error {\n\tif outPath == \"\" {\n\t\treturn fmt.Errorf(\"report path is required\")\n\t}\n\traw, err := json.Marshal(report)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"encode stats report: %w\", err)\n\t}\n\tif err := os.MkdirAll(filepath.Dir(outPath), 0o700); err != nil {\n\t\treturn err\n\t}\n\tf, err := os.CreateTemp(filepath.Dir(outPath), \".caveman-stats-*.html\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer os.Remove(f.Name())\n\t// encoding/json escapes <, >, &, and JavaScript line separators. Mark only\n\t// its output as JavaScript: an untrusted model name cannot close the script.\n\terr = statsReportTemplate.Execute(f, struct{ Data template.JS }{Data: template.JS(raw)})\n\tif closeErr := f.Close(); err == nil {\n\t\terr = closeErr\n\t}\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/store/stats_report.go#L5-L41","documentation":"WriteStatsHTML serializes a StatsReport to JSON before rendering it to an HTML file. This error wraps any failure from json.Marshal of the report. It means the StatsReport itself could not be encoded, typically because it contains a value JSON cannot represent (unsupported types, cyclic references, or a custom MarshalJSON that failed).","triggerScenarios":"Calling Store.WriteStatsHTML(report, outPath) with a StatsReport containing a field that json.Marshal cannot encode — e.g. a channel, func, complex number, cyclic pointer graph, or a field whose MarshalJSON returns an error.","commonSituations":"Developers add a custom type to StatsReport with a buggy MarshalJSON, or stuff a non-serializable runtime value (map with non-string keys of unsupported kind, func) into a report field before calling WriteStatsHTML.","solutions":["Marshal the report yourself first (json.Marshal(report)) to see the underlying encoding error message.","Audit the StatsReport fields added most recently for unsupported types or a failing MarshalJSON.","Add json:\"...\" tags and ensure all map keys and field types are JSON-encodable (strings/ints/floats/bools/slices/nested structs).","If a custom MarshalJSON exists on any report type, fix it to return valid JSON or nil error."],"exampleFix":"// before\ntype StatsReport struct {\n    Extra map[int]string // unsupported key type\n}\n// after\ntype StatsReport struct {\n    Extra map[string]string `json:\"extra,omitempty\"`\n}","handlingStrategy":"try-catch","validationCode":"if _, err := json.Marshal(report); err != nil {\n    // report is not encodable; fix fields before calling WriteStatsHTML\n}","typeGuard":null,"tryCatchPattern":"if err := s.WriteStatsHTML(report, outPath); err != nil {\n    if strings.Contains(err.Error(), \"encode stats report\") {\n        log.Printf(\"report not JSON-encodable: %v\", err) // inspect wrapped cause\n    }\n}","preventionTips":["Keep StatsReport fields restricted to JSON-native types.","Add unit tests that marshal a fully populated StatsReport.","Avoid custom MarshalJSON on report types unless well tested."],"tags":["json","encoding","stats-report"],"backgroundTag":"json-marshal-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}