JuliusBrussee/caveman · error

row limit %d exceeded

Error message

row limit %d exceeded

What it means

appendCorpusRow refuses to add another row because the number of accumulated rows has already reached limits.MaxRows. This is a hard cap that keeps the in-memory corpus bounded; the check fires before the row is appended, so the corpus stays at exactly MaxRows.

Source

Thrown at cacheengine/cachebench/corpus.go:390

	}
	for _, call := range message.ToolCalls {
		if call.Type != "function" || !validBoundedText(call.ID, 2048, false) || !validBoundedText(call.Function.Name, 512, false) || !validUniqueJSONObject([]byte(call.Function.Arguments)) {
			return errors.New("tool call requires function type, id, function name, and JSON arguments")
		}
		messageBytes += len(call.ID) + len(call.Type) + len(call.Function.Name) + len(call.Function.Arguments)
	}
	if messageBytes > limits.MaxMessageBytes {
		return errors.New("message exceeds byte limit")
	}
	if message.Role == "tool" && message.ToolCallID == "" {
		return errors.New("tool message requires tool_call_id")
	}
	return nil
}

func appendCorpusRow(rows *[]CorpusRow, sessions map[string]bool, retainedBytes *int64, row CorpusRow, limits CorpusLimits) error {
	if len(*rows) >= limits.MaxRows {
		return fmt.Errorf("row limit %d exceeded", limits.MaxRows)
	}
	if !sessions[row.SessionID] {
		if len(sessions) >= limits.MaxSessions {
			return fmt.Errorf("session limit %d exceeded", limits.MaxSessions)
		}
		sessions[row.SessionID] = true
	}
	rowBytes := corpusRowRetainedBytes(row)
	if rowBytes > limits.MaxRetainedBytes-*retainedBytes {
		return fmt.Errorf("retained corpus byte limit %d exceeded", limits.MaxRetainedBytes)
	}
	*retainedBytes += rowBytes
	*rows = append(*rows, row)
	return nil
}

func corpusRetainedBytes(rows []CorpusRow) int64 {
	var total int64

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Raise CorpusLimits.MaxRows to cover the corpus size (count lines in the JSONL first).
  2. Split the corpus file into shards each within MaxRows and load them separately.
  3. Subsample the corpus to fit the current cap using the tool's own sampling/export options.

Example fix

// before
limits.MaxRows = 10_000
// after
limits.MaxRows = 100_000
Defensive patterns

Strategy: validation

Validate before calling

func countCorpusRows(path string) (int, error) {
	f, err := os.Open(path)
	if err != nil {
		return 0, err
	}
	defer f.Close()
	n := 0
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		if len(bytes.TrimSpace(scanner.Bytes())) > 0 {
			n++
		}
	}
	return n, scanner.Err()
}

// before loading:
// n, _ := countCorpusRows(path); if n > limits.MaxRows { limits.MaxRows = n }

Prevention

When it happens

Trigger: Loading a corpus whose row count exceeds CorpusLimits.MaxRows: on the (MaxRows+1)-th call to appendCorpusRow, len(*rows) >= MaxRows and the error is returned.

Common situations: Pointing the loader at a larger capture file than the configured budget allows, or reusing tight default limits with a production-sized trace.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/f02483212d66ce72. Report an issue: GitHub.