alibaba/open-code-review · error

grouping LLM panicked: %v

Error message

grouping LLM panicked: %v

What it means

callGroupingLLM installs a deferred recover() and, if the grouping LLM call path panics (nil pointer, index out of range, nil map write in response handling, etc.), converts the panic into this error and clears the task record response. This prevents a panic in LLM response processing from crashing the whole review process.

Source

Thrown at internal/agent/grouping.go:173

// FileGroup exists, so it describes the change set the way review.started does,
// rather than the group-scoped spans that pair group.file_count with a
// group.label there is none of here.
func emitGroupingSkipped(ctx context.Context, strategy template.GroupingStrategy, fileCount int, totalChanged int64, tpl template.Template) {
	telemetry.Event(ctx, "grouping.skipped",
		telemetry.AnyToAttr("strategy", strategy.String()),
		telemetry.AnyToAttr("file.count", fileCount),
		telemetry.AnyToAttr("lines.changed", totalChanged),
		telemetry.AnyToAttr("threshold.files", tpl.GroupingMinFiles),
		telemetry.AnyToAttr("threshold.lines", tpl.GroupingBundleLineThreshold))
}

func callGroupingLLM(ctx context.Context, diffs []model.Diff, client llm.LLMClient, modelName string, task *template.LlmConversation, maxTokens int, sessOpts *groupingSessionOpts) (groups []FileGroup, usage *llm.UsageInfo, err error) {
	var rec *session.TaskRecord
	startTime := time.Now()
	defer func() {
		if r := recover(); r != nil {
			groups = nil
			err = fmt.Errorf("grouping LLM panicked: %v", r)
			if rec != nil {
				rec.Response = nil
				rec.SetError(err, time.Since(startTime))
			}
		}
	}()

	fileList := buildFileList(diffs)

	messages := make([]llm.Message, 0, len(task.Messages))
	for _, m := range task.Messages {
		content := strings.ReplaceAll(m.Content, "{{file_list}}", fileList)
		messages = append(messages, llm.NewTextMessage(m.Role, content))
	}

	const groupingFileKey = "__grouping__"

	if sessOpts != nil && sessOpts.session != nil {

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Look at the %v value in the message — it names the panic (e.g. 'runtime error: invalid memory address').
  2. Check the session task record; rec.Response is cleared, so rely on the error string and logs.
  3. Re-run; if reproducible, inspect the LLM response that triggered it (enable debug logging) and the template configuration.
  4. Report as a bug with the panic text and model/provider if input is well-formed — the recover is a safety net, not an expected path.
Defensive patterns

Strategy: try-catch

Try / catch

// the library already recovers; callers should treat the returned error as fatal-but-safe
if groups, _, err := callGroupingLLM(ctx, diffs, client, model, task, maxTokens, opts); err != nil {
    log.Printf("grouping failed: %v", err) // includes panic text after 'grouping LLM panicked:'
    return fallbackGrouping(diffs)
}

Prevention

When it happens

Trigger: A panic anywhere between callGroupingLLM entry and return — typically while handling a malformed/nil LLM response or usage object inside the grouping call path.

Common situations: Provider SDK returning an unexpected response shape (nil resp dereferenced), template misconfiguration causing nil message slices, or a bug triggered by an unusual API response (e.g. resp with nil Usage accessed by recoverable code).

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/1ab02172a3fac107. Report an issue: GitHub.