{"record":{"id":"6caa2a858786cfdb","repo":"micro/go-micro","slug":"flow-untilllm-requires-a-flow-model-set-provider","errorCode":null,"errorMessage":"flow: UntilLLM requires a flow model (set Provider/APIKey)","messagePattern":"flow: UntilLLM requires a flow model \\(set Provider/APIKey\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"flow/loop.go","lineNumber":128,"sourceCode":"func loopDone(ctx context.Context, o LoopOptions, state State, iter int) (bool, error) {\n\tif o.Until != nil {\n\t\tdone, err := o.Until(ctx, state, iter)\n\t\tif err != nil || done {\n\t\t\treturn done, err\n\t\t}\n\t}\n\tif o.UntilLLM != \"\" {\n\t\treturn askDone(ctx, o.UntilLLM, state)\n\t}\n\treturn false, nil\n}\n\n// askDone asks the flow model whether the goal is met given the current\n// state, and returns true on an affirmative reply — the supervised stop check.\nfunc askDone(ctx context.Context, question string, state State) (bool, error) {\n\td := depsFrom(ctx)\n\tif d == nil || d.model == nil {\n\t\treturn false, fmt.Errorf(\"flow: UntilLLM requires a flow model (set Provider/APIKey)\")\n\t}\n\tprompt := fmt.Sprintf(\"%s\\n\\nLatest result:\\n%s\\n\\nAnswer with only \\\"yes\\\" or \\\"no\\\".\", question, state.String())\n\tresp, err := d.model.Generate(ctx, &ai.Request{Prompt: prompt})\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treply := resp.Answer\n\tif reply == \"\" {\n\t\treply = resp.Reply\n\t}\n\treturn isAffirmative(reply), nil\n}\n\n// isAffirmative reports whether a model reply reads as \"yes/done\".\nfunc isAffirmative(s string) bool {\n\ts = strings.ToLower(strings.TrimSpace(s))\n\tfor _, p := range []string{\"yes\", \"done\", \"true\", \"complete\", \"finished\"} {\n\t\tif strings.HasPrefix(s, p) {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/flow/loop.go#L110-L146","documentation":"The UntilLLM loop's supervised stop check (askDone, via loopDone) needs the flow model to judge whether the goal is met, but no model was found in the context dependencies. The library tells you exactly which flow settings are missing: Provider and/or APIKey.","triggerScenarios":"Running a UntilLLM loop when the context carries no deps or deps.model is nil — i.e. the flow was created without Provider/APIKey, or the model wasn't injected into the context before the step executed.","commonSituations":"Using UntilLLM in a flow constructed with an empty Provider config; running steps outside the normal flow execution path so the context lacks model deps; a nil model caused by an unknown provider (related to error 304).","solutions":["Set Provider and APIKey in the flow options so the flow model is initialized.","If running steps manually, inject the model deps into the context as UntilLLM expects.","Verify ai.New returned a non-nil model (see error 304) before using UntilLLM.","Use a non-LLM stop condition (max iterations or a done predicate) when no model is available."],"exampleFix":"// before\nf, _ := flow.New(\"myflow\") // no provider\nf.UntilLLM(\"Is the goal met?\")\n// after\nf, _ := flow.New(\"myflow\", flow.Provider(\"openai\"), flow.APIKey(os.Getenv(\"OPENAI_API_KEY\")))\nf.UntilLLM(\"Is the goal met?\")","handlingStrategy":"validation","validationCode":"if cfg.Provider == \"\" || cfg.APIKey == \"\" {\n\treturn errors.New(\"UntilLLM requires flow Provider and APIKey to be set\")\n}","typeGuard":"func untilLLMReady(ctx context.Context) bool {\n\td := depsFrom(ctx)\n\treturn d != nil && d.model != nil\n}","tryCatchPattern":"done, err := loopDone(ctx, opts, state, iter)\nif err != nil && strings.Contains(err.Error(), \"requires a flow model\") {\n\t// fall back to a non-LLM stop condition\n\tdone = iter >= opts.Max\n}","preventionTips":["Validate Provider/APIKey at flow construction, before any UntilLLM step runs.","Run UntilLLM loops only through the normal flow execution path that injects model deps.","Provide a fallback done-predicate for environments without model credentials."],"tags":["flow","llm","until","configuration"],"backgroundTag":"missing-model-configuration","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}