{"record":{"id":"2cfb2df54859cd4c","repo":"alibaba/open-code-review","slug":"grouping-llm-returned-empty-response","errorCode":null,"errorMessage":"grouping LLM returned empty response","messagePattern":"grouping LLM returned empty response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/grouping.go","lineNumber":228,"sourceCode":"\t\tModel:     modelName,\n\t\tMessages:  messages,\n\t\tMaxTokens: maxTokens,\n\t})\n\tduration := time.Since(startTime)\n\n\tif err != nil {\n\t\tif rec != nil {\n\t\t\trec.SetError(err, duration)\n\t\t}\n\t\treturn nil, nil, fmt.Errorf(\"grouping LLM call: %w\", err)\n\t}\n\n\tusage = resp.Usage\n\n\tcontent := resp.Content()\n\tif content == \"\" {\n\t\tif rec != nil {\n\t\t\trec.SetError(fmt.Errorf(\"grouping LLM returned empty response\"), duration)\n\t\t}\n\t\treturn nil, usage, fmt.Errorf(\"grouping LLM returned empty response\")\n\t}\n\n\tgroups, err = parseGroupingResponse(content, diffs)\n\tif rec != nil {\n\t\tif err != nil {\n\t\t\trec.SetError(fmt.Errorf(\"grouping response parse failed: %w\", err), duration)\n\t\t} else {\n\t\t\trec.SetResponse(resp, duration)\n\t\t}\n\t}\n\treturn groups, usage, err\n}\n\nfunc buildFileList(diffs []model.Diff) string {\n\tvar sb strings.Builder\n\tfor _, d := range diffs {","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/agent/grouping.go#L210-L246","documentation":"When the grouping LLM responds successfully but the response content is an empty string, callGroupingLLM records this error on the session task record (rec.SetError) so the persisted history shows the failed attempt, before returning the same error to the caller. It means the API call succeeded but the model produced no usable text to parse into file groups.","triggerScenarios":"callGroupingLLM receiving resp.Content() == \"\" — e.g. the model returned only a stop token, a tool call with no text, or the provider stripped the content due to a content filter or max_tokens=0-equivalent truncation.","commonSituations":"maxTokens configured too low (TestCallGroupingLLM_UsesTemplateMaxTokens suggests template-driven limits) so output is truncated to nothing; provider content-filter suppression; wrong model that doesn't follow the grouping prompt at all.","solutions":["Increase the template's max token limit for the grouping task so the model has room to answer.","Re-run; empty responses are often transient (sampled stop token).","Verify the model supports the grouping prompt format and is not a tool-only model.","Check provider logs/dashboard for content-filter flags on the request."],"exampleFix":"// before\ngrouping maxTokens: 16  // model emits only a stop token\n// after\ngrouping maxTokens: 2048 // template completion limit sized for the grouping JSON","handlingStrategy":"retry","validationCode":"// ensure the template's grouping token limit is large enough before running\nif template.GroupingMaxTokens < 512 { return fmt.Errorf(\"grouping max tokens too small (%d)\", template.GroupingMaxTokens) }","typeGuard":"func hasContent(resp *llm.ChatResponse) bool { return resp != nil && resp.Content() != \"\" }","tryCatchPattern":"if _, _, err := callGroupingLLM(...); err != nil && strings.Contains(err.Error(), \"empty response\") {\n    // retry once; empty completions are often transient\n}","preventionTips":["Size max_tokens for the grouping JSON output, not the input.","Prefer models that reliably emit final text for the grouping prompt format.","Retry once on empty responses before failing the run.","Check provider content-filter flags if empty responses recur."],"tags":["llm","empty-response","grouping","tokens"],"backgroundTag":"llm-empty-response","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}