vxcontrol/pentagi · error

failed to add assistant to flow: %w

Error message

failed to add assistant to flow: %w

What it means

Wrap in CreateAssistant when fw.AddAssistant(ctx, aw) fails after the assistant worker was successfully created. AddAssistant registers the assistant with the flow worker (its internal tracking/subscriber state); failure means the assistant exists but is not attached to the flow, so the controller returns an error instead of a half-registered assistant.

Source

Thrown at backend/pkg/controller/flows.go:324

	aw, err := NewAssistantWorker(ctx, newAssistantWorkerCtx{
		userID:        userID,
		flowID:        flowID,
		input:         input,
		prvname:       prvname,
		prvtype:       prvtype,
		useAgents:     useAgents,
		functions:     functions,
		resources:     resources,
		fw:            fw,
		flowWorkerCtx: flowWorkerCtx,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create assistant: %w", err)
	}

	if err = fw.AddAssistant(ctx, aw); err != nil {
		return nil, fmt.Errorf("failed to add assistant to flow: %w", err)
	}

	return aw, nil
}

func (fc *flowController) ListFlows(ctx context.Context) []FlowWorker {
	fc.mx.Lock()
	defer fc.mx.Unlock()

	flows := make([]FlowWorker, 0)
	for _, flow := range fc.flows {
		flows = append(flows, flow)
	}

	sort.Slice(flows, func(i, j int) bool {
		return flows[i].GetFlowID() < flows[j].GetFlowID()
	})

View on GitHub (pinned to ea665308ba)

Solutions

  1. Retry CreateAssistant; transient races with flow shutdown resolve on a new attempt.
  2. Ensure no concurrent StopFlow/FinishFlow is running for this flowID while adding assistants.
  3. Check backend logs for the wrapped AddAssistant cause (subscriber/state errors).
  4. If the flow is being torn down, create a new flow instead of reusing it.

Example fix

// before
// concurrent stop race
wg.Add(2)
go ctl.StopFlow(ctx, flowID)
go ctl.CreateAssistant(ctx, userID, flowID, ...) // may fail here
// after
// serialize: add assistant first, then stop if needed
aw, err := ctl.CreateAssistant(ctx, userID, flowID, ...)
if err == nil { go ctl.StopFlow(ctx, flowID) }
Defensive patterns

Strategy: retry

Try / catch

var aw AssistantWorker
err := retry(3, backoff, func() error {
    var e error
    aw, e = ctl.CreateAssistant(ctx, userID, flowID, ...)
    if e != nil && strings.Contains(e.Error(), "failed to add assistant to flow") {
        return e // transient race, retry
    }
    return nil //nolint: do not retry other causes
})

Prevention

When it happens

Trigger: CreateAssistant succeeds through worker creation but fw.AddAssistant errors — e.g. the flow worker's internal state is being torn down concurrently, its assistant registry rejects the addition, or a context cancellation aborts the registration.

Common situations: Stopping the flow at the same moment an assistant is created (race between StopFlow and CreateAssistant), a flow worker that was closed after status checks, or context cancellation mid-registration.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/60158d472cd5ea99. Report an issue: GitHub.