JuliusBrussee/caveman · error

report path is required

Error message

report path is required

What it means

WriteStatsHTML writes a private, self-contained stats snapshot HTML file at outPath, rolling up only recorded metric groups. An empty outPath is rejected with 'report path is required' before encoding or writing anything. The page never derives prices, so a path must be supplied explicitly for the snapshot to land somewhere meaningful.

Solutions

  1. Pass a concrete output path for the stats HTML snapshot
  2. Set the flag/config value that supplies the path before invoking the command
  3. Validate non-empty in the caller and emit a usage error when blank

Example fix

// before
if err := store.WriteStatsHTML(report, outPath); err != nil { ... } // outPath == ""
// after
if outPath == "" {
    return fmt.Errorf("--out is required for the stats report")
}
if err := store.WriteStatsHTML(report, outPath); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

if outPath == "" { return fmt.Errorf("stats report output path is required") }

Prevention

When it happens

Trigger: Calling WriteStatsHTML (directly or via runStatsReport) with an empty outPath, typically when the stats report output flag was omitted.

Common situations: Missing --out flag in a scheduled stats snapshot job; empty path in a wrapper script; regression after refactoring where the default output path was removed.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/ae0612fa997f13ca. Report an issue: GitHub.

Appendix: source

Thrown at proxy/internal/store/stats_report.go:19

package store

import (
	"encoding/json"
	"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

View on GitHub (pinned to 3ee70a1026)