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
- Look at the %v value in the message — it names the panic (e.g. 'runtime error: invalid memory address').
- Check the session task record; rec.Response is cleared, so rely on the error string and logs.
- Re-run; if reproducible, inspect the LLM response that triggered it (enable debug logging) and the template configuration.
- 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
- Keep the LLM client/provider SDK versions in sync with this library to avoid unexpected response shapes.
- Enable debug logging of raw responses when investigating reproducible panics.
- Do not pass nil template/session options into the pipeline.
- Report panics with the exact %v text — recovery masks the stack trace, so logs matter.
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
- grouping LLM call: %w
- grouping LLM returned empty response
- grouping response parse failed: %w
- parse grouping JSON: %w
- resolve LLM endpoint: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/1ab02172a3fac107.
Report an issue: GitHub.