micro/go-micro · error

flow: UntilLLM requires a flow model (set Provider/APIKey)

Error message

flow: UntilLLM requires a flow model (set Provider/APIKey)

What it means

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.

Source

Thrown at flow/loop.go:128

func loopDone(ctx context.Context, o LoopOptions, state State, iter int) (bool, error) {
	if o.Until != nil {
		done, err := o.Until(ctx, state, iter)
		if err != nil || done {
			return done, err
		}
	}
	if o.UntilLLM != "" {
		return askDone(ctx, o.UntilLLM, state)
	}
	return false, nil
}

// askDone asks the flow model whether the goal is met given the current
// state, and returns true on an affirmative reply — the supervised stop check.
func askDone(ctx context.Context, question string, state State) (bool, error) {
	d := depsFrom(ctx)
	if d == nil || d.model == nil {
		return false, fmt.Errorf("flow: UntilLLM requires a flow model (set Provider/APIKey)")
	}
	prompt := fmt.Sprintf("%s\n\nLatest result:\n%s\n\nAnswer with only \"yes\" or \"no\".", question, state.String())
	resp, err := d.model.Generate(ctx, &ai.Request{Prompt: prompt})
	if err != nil {
		return false, err
	}
	reply := resp.Answer
	if reply == "" {
		reply = resp.Reply
	}
	return isAffirmative(reply), nil
}

// isAffirmative reports whether a model reply reads as "yes/done".
func isAffirmative(s string) bool {
	s = strings.ToLower(strings.TrimSpace(s))
	for _, p := range []string{"yes", "done", "true", "complete", "finished"} {
		if strings.HasPrefix(s, p) {

View on GitHub (pinned to 24529f1404)

Solutions

  1. Set Provider and APIKey in the flow options so the flow model is initialized.
  2. If running steps manually, inject the model deps into the context as UntilLLM expects.
  3. Verify ai.New returned a non-nil model (see error 304) before using UntilLLM.
  4. Use a non-LLM stop condition (max iterations or a done predicate) when no model is available.

Example fix

// before
f, _ := flow.New("myflow") // no provider
f.UntilLLM("Is the goal met?")
// after
f, _ := flow.New("myflow", flow.Provider("openai"), flow.APIKey(os.Getenv("OPENAI_API_KEY")))
f.UntilLLM("Is the goal met?")
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Provider == "" || cfg.APIKey == "" {
	return errors.New("UntilLLM requires flow Provider and APIKey to be set")
}

Type guard

func untilLLMReady(ctx context.Context) bool {
	d := depsFrom(ctx)
	return d != nil && d.model != nil
}

Try / catch

done, err := loopDone(ctx, opts, state, iter)
if err != nil && strings.Contains(err.Error(), "requires a flow model") {
	// fall back to a non-LLM stop condition
	done = iter >= opts.Max
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/6caa2a858786cfdb. Report an issue: GitHub.