JuliusBrussee/caveman · error

session limit %d exceeded

Error message

session limit %d exceeded

What it means

A new session ID appeared after the session cap was already reached: appendCorpusRow only registers unseen session IDs, and it refuses when len(sessions) >= limits.MaxSessions. Existing sessions can keep adding rows; only distinct new sessions are blocked.

Source

Thrown at cacheengine/cachebench/corpus.go:394

		}
		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
	for _, row := range rows {
		total += corpusRowRetainedBytes(row)
	}
	return total

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Increase CorpusLimits.MaxSessions to the number of distinct session IDs in the file.
  2. Normalize/merge session IDs before loading if IDs were split artificially.
  3. Filter the corpus to the sessions you actually want to benchmark.

Example fix

// before
limits.MaxSessions = 50
// after
limits.MaxSessions = 5_000
Defensive patterns

Strategy: validation

Validate before calling

func countSessions(path string) (int, error) {
	f, err := os.Open(path)
	if err != nil {
		return 0, err
	}
	defer f.Close()
	seen := map[string]bool{}
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		var row struct{ SessionID string `json:"session_id"` }
		if json.Unmarshal(scanner.Bytes(), &row) == nil && row.SessionID != "" {
			seen[row.SessionID] = true
		}
	}
	return len(seen), scanner.Err()
}

Prevention

When it happens

Trigger: A corpus row arrives whose SessionID has not been seen before while limits.MaxSessions distinct sessions are already registered.

Common situations: Replaying a wide fleet capture with many short sessions against limits tuned for a few long sessions; session IDs that change format (e.g. new suffix) after a provider migration, inflating distinct-session counts.

Related errors


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