JuliusBrussee/caveman · error

usage export has no header row: %w

Error message

usage export has no header row: %w

What it means

The csv.Reader returned an error on its first Read in parseUsageExport, meaning the file has no parseable header row — typically an empty file or unreadable/binary content. The wrapped error carries the CSV parser's reason.

Source

Thrown at proxy/internal/store/learn_reconcile.go:144

	value, err := strconv.ParseFloat(raw, 64)
	if err != nil || value < 0 {
		return 0
	}
	return int64(value)
}

// parseUsageExport reads a provider usage CSV into billed tokens per model.
func parseUsageExport(path string) (map[string]int64, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("read usage export: %w", err)
	}
	defer file.Close()
	reader := csv.NewReader(file)
	reader.FieldsPerRecord = -1
	header, err := reader.Read()
	if err != nil {
		return nil, fmt.Errorf("usage export has no header row: %w", err)
	}
	columns, err := mapReconcileHeader(header)
	if err != nil {
		return nil, err
	}
	billed := map[string]int64{}
	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("usage export row: %w", err)
		}
		modelIndex := columns["model"]
		if modelIndex >= len(record) {
			continue
		}

View on GitHub (pinned to 81536f57b3)

Solutions

  1. Check the usage export file is a non-empty CSV with a header row
  2. Re-export from the provider; the file may be truncated or empty
  3. Ensure the path points to the CSV, not a directory or binary file
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at proxy/internal/store/learn_reconcile.go:144 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of JuliusBrussee/caveman@81536f57b3 (2026-08-27). Data as JSON: /api/errors/4467cbc4a542316f. Report an issue: GitHub.