JuliusBrussee/caveman · error
encode stats report
Error message
encode stats report: %w
What it means
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).
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.
Example fix
// before
type StatsReport struct {
Extra map[int]string // unsupported key type
}
// after
type StatsReport struct {
Extra map[string]string `json:"extra,omitempty"`
} Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := json.Marshal(report); err != nil {
// report is not encodable; fix fields before calling WriteStatsHTML
} Try / catch
if err := s.WriteStatsHTML(report, outPath); err != nil {
if strings.Contains(err.Error(), "encode stats report") {
log.Printf("report not JSON-encodable: %v", err) // inspect wrapped cause
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- array not closed
- not losslessly TOON-encodable (invalid JSON, or…
- unexpected delimiter
- unsupported token %T
- assembly slot content is not JSON-serializable
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/b88c6717aa8430d8.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/internal/store/stats_report.go:23
"fmt"
"html/template"
"os"
"path/filepath"
)
func DefaultStatsReportPath(home string) string {
return filepath.Join(home, "reports", "caveman-stats.html")
}
// WriteStatsHTML writes a private, self-contained snapshot. The page only rolls
// up recorded metric groups; it never derives a price or upgrades evidence.
func (s *Store) WriteStatsHTML(report StatsReport, outPath string) error {
if outPath == "" {
return fmt.Errorf("report path is required")
}
raw, err := json.Marshal(report)
if err != nil {
return fmt.Errorf("encode stats report: %w", err)
}
if err := os.MkdirAll(filepath.Dir(outPath), 0o700); err != nil {
return err
}
f, err := os.CreateTemp(filepath.Dir(outPath), ".caveman-stats-*.html")
if err != nil {
return err
}
defer os.Remove(f.Name())
// encoding/json escapes <, >, &, and JavaScript line separators. Mark only
// its output as JavaScript: an untrusted model name cannot close the script.
err = statsReportTemplate.Execute(f, struct{ Data template.JS }{Data: template.JS(raw)})
if closeErr := f.Close(); err == nil {
err = closeErr
}
if err != nil {
return err
}View on GitHub (pinned to 3ee70a1026)