{"record":{"id":"015f7e8e8ca3387a","repo":"micro/go-micro","slug":"flow-llmoptimizer-returned-an-empty-prompt","errorCode":null,"errorMessage":"flow: LLMOptimizer returned an empty prompt","messagePattern":"flow: LLMOptimizer returned an empty prompt","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"flow/analyze.go","lineNumber":171,"sourceCode":"\n// OptimizePrompt asks the model for a revised prompt for candidate using the\n// current prompt and trace feedback. It returns only the proposal; it never\n// modifies a Flow, Step, or Checkpoint.\nfunc (o *PromptOptimizer) OptimizePrompt(ctx context.Context, candidate Candidate, currentPrompt string) (string, error) {\n\tif o == nil || o.model == nil {\n\t\treturn \"\", fmt.Errorf(\"flow: LLMOptimizer requires a model\")\n\t}\n\tprompt := fmt.Sprintf(\"Revise this workflow step prompt to improve the failing step.\\nStep: %s\\nMetric: %s\\nScore: %.2f\\nFeedback:\\n- %s\\n\\nCurrent prompt:\\n%s\\n\\nReturn only the revised prompt.\", candidate.Step, candidate.Metric, candidate.Score, strings.Join(candidate.SampleFeedback, \"\\n- \"), currentPrompt)\n\tresp, err := o.model.Generate(ctx, &ai.Request{Prompt: prompt})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tproposal := strings.TrimSpace(resp.Answer)\n\tif proposal == \"\" {\n\t\tproposal = strings.TrimSpace(resp.Reply)\n\t}\n\tif proposal == \"\" {\n\t\treturn \"\", fmt.Errorf(\"flow: LLMOptimizer returned an empty prompt\")\n\t}\n\treturn proposal, nil\n}\n\nfunc verificationFields(result string) (bool, string, bool) {\n\tif result == \"\" {\n\t\treturn false, \"\", false\n\t}\n\tvar obj map[string]any\n\tif err := json.Unmarshal([]byte(result), &obj); err != nil {\n\t\treturn false, \"\", false\n\t}\n\tv, ok := obj[\"verification_passed\"].(bool)\n\tif !ok {\n\t\treturn false, \"\", false\n\t}\n\tfb, _ := obj[\"verification_feedback\"].(string)\n\treturn v, fb, true","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/flow/analyze.go#L153-L189","documentation":"The model responded successfully to the prompt-revision request, but its Answer (and fallback Reply) contained only whitespace or was empty. The library refuses to return an empty proposal since replacing a prompt with empty text would break the workflow step.","triggerScenarios":"Calling OptimizePrompt when the model returns an empty string — e.g. the model hit a content filter, the response was truncated to nothing, or a misconfigured provider returned a 200 with no body content.","commonSituations":"Using a provider that populates a different response field than Answer/Reply; very small models that emit blank output; token limits causing empty completions; proxy/gateway stripping the response body.","solutions":["Check the model response fields your provider actually populates (Answer vs Reply) and confirm the adapter maps them.","Increase max tokens / reduce prompt size so the model can produce output.","Switch to a stronger model or retry the Generate call; transient empty completions are common.","Log resp.Answer and resp.Reply to confirm what the model returned before failing."],"exampleFix":"// before\nresp, err := o.model.Generate(ctx, &ai.Request{Prompt: prompt}) // tiny model, max_tokens:1\n// after\nresp, err := o.model.Generate(ctx, &ai.Request{Prompt: prompt, Options: map[string]any{\"max_tokens\": 512}})","handlingStrategy":"retry","validationCode":"if resp != nil && strings.TrimSpace(resp.Answer) == \"\" && strings.TrimSpace(resp.Reply) == \"\" {\n\treturn errors.New(\"model returned empty answer; retrying\")\n}","typeGuard":"func hasProposal(resp *ai.Response) bool {\n\treturn resp != nil && (strings.TrimSpace(resp.Answer) != \"\" || strings.TrimSpace(resp.Reply) != \"\")\n}","tryCatchPattern":"prompt, err := opt.OptimizePrompt(ctx, cand, current)\nif err != nil && strings.Contains(err.Error(), \"empty prompt\") {\n\tprompt, err = opt.OptimizePrompt(ctx, cand, current) // one retry on transient empty completion\n\tif err != nil { prompt = current }\n}","preventionTips":["Set adequate max_tokens for revision requests.","Prefer models known to produce non-empty structured output.","Log raw model responses to detect providers that populate alternate fields."],"tags":["flow","ai","empty-response"],"backgroundTag":"llm-empty-response","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}