{"record":{"id":"f02483212d66ce72","repo":"JuliusBrussee/caveman","slug":"row-limit-d-exceeded","errorCode":null,"errorMessage":"row limit %d exceeded","messagePattern":"row limit (.+?) exceeded","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cacheengine/cachebench/corpus.go","lineNumber":390,"sourceCode":"\t}\n\tfor _, call := range message.ToolCalls {\n\t\tif call.Type != \"function\" || !validBoundedText(call.ID, 2048, false) || !validBoundedText(call.Function.Name, 512, false) || !validUniqueJSONObject([]byte(call.Function.Arguments)) {\n\t\t\treturn errors.New(\"tool call requires function type, id, function name, and JSON arguments\")\n\t\t}\n\t\tmessageBytes += len(call.ID) + len(call.Type) + len(call.Function.Name) + len(call.Function.Arguments)\n\t}\n\tif messageBytes > limits.MaxMessageBytes {\n\t\treturn errors.New(\"message exceeds byte limit\")\n\t}\n\tif message.Role == \"tool\" && message.ToolCallID == \"\" {\n\t\treturn errors.New(\"tool message requires tool_call_id\")\n\t}\n\treturn nil\n}\n\nfunc appendCorpusRow(rows *[]CorpusRow, sessions map[string]bool, retainedBytes *int64, row CorpusRow, limits CorpusLimits) error {\n\tif len(*rows) >= limits.MaxRows {\n\t\treturn fmt.Errorf(\"row limit %d exceeded\", limits.MaxRows)\n\t}\n\tif !sessions[row.SessionID] {\n\t\tif len(sessions) >= limits.MaxSessions {\n\t\t\treturn fmt.Errorf(\"session limit %d exceeded\", limits.MaxSessions)\n\t\t}\n\t\tsessions[row.SessionID] = true\n\t}\n\trowBytes := corpusRowRetainedBytes(row)\n\tif rowBytes > limits.MaxRetainedBytes-*retainedBytes {\n\t\treturn fmt.Errorf(\"retained corpus byte limit %d exceeded\", limits.MaxRetainedBytes)\n\t}\n\t*retainedBytes += rowBytes\n\t*rows = append(*rows, row)\n\treturn nil\n}\n\nfunc corpusRetainedBytes(rows []CorpusRow) int64 {\n\tvar total int64","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/cacheengine/cachebench/corpus.go#L372-L408","documentation":"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.","triggerScenarios":"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.","commonSituations":"Pointing the loader at a larger capture file than the configured budget allows, or reusing tight default limits with a production-sized trace.","solutions":["Raise CorpusLimits.MaxRows to cover the corpus size (count lines in the JSONL first).","Split the corpus file into shards each within MaxRows and load them separately.","Subsample the corpus to fit the current cap using the tool's own sampling/export options."],"exampleFix":"// before\nlimits.MaxRows = 10_000\n// after\nlimits.MaxRows = 100_000","handlingStrategy":"validation","validationCode":"func countCorpusRows(path string) (int, error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer f.Close()\n\tn := 0\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tif len(bytes.TrimSpace(scanner.Bytes())) > 0 {\n\t\t\tn++\n\t\t}\n\t}\n\treturn n, scanner.Err()\n}\n\n// before loading:\n// n, _ := countCorpusRows(path); if n > limits.MaxRows { limits.MaxRows = n }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Count corpus lines and compare against MaxRows before loading.","Derive limits from corpus metadata instead of hard-coding them.","Shard large corpora rather than loosening caps ad hoc."],"tags":["go","limits","corpus","configuration"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}