vxcontrol/pentagi · error

failed to update flow provider in DB: %w

Error message

failed to update flow provider in DB: %w

What it means

After a successful in-memory SetProvider, switchProvider persists the new provider name/type, resolved tool_call_id_template and primary-agent model to the flows table via UpdateFlowProvider. This error means the DB write failed, so the flow runs on the new provider in memory but a restart would revert it — memory and database are inconsistent until fixed.

Source

Thrown at backend/pkg/controller/flow.go:927

		logger.Debug("provider is the same, skipping switch")
		return nil
	}

	logger.Info("switching flow provider")

	// Every persisted value is taken from prv (and the template SetProvider
	// resolved for it) rather than re-read from the shared flow provider, so a
	// concurrent switch cannot interleave into a mixed-provider row.
	flow, err := fw.flowCtx.DB.UpdateFlowProvider(ctx, database.UpdateFlowProviderParams{
		ModelProviderName:  prv.Name().String(),
		ModelProviderType:  database.ProviderType(prv.Type()),
		ToolCallIDTemplate: tcIDTemplate,
		Model:              prv.Model(pconfig.OptionsTypePrimaryAgent),
		ID:                 fw.flowCtx.FlowID,
	})
	if err != nil {
		logger.WithError(err).Error("failed to update flow provider in DB")
		return fmt.Errorf("failed to update flow provider in DB: %w", err)
	}

	logger.WithFields(logrus.Fields{
		"new_tool_call_id_template": tcIDTemplate,
		"new_model":                 prv.Model(pconfig.OptionsTypePrimaryAgent),
	}).Info("provider switched successfully")

	if containers, err := fw.flowCtx.DB.GetFlowContainers(ctx, fw.flowCtx.FlowID); err == nil {
		fw.flowCtx.Publisher.FlowUpdated(ctx, flow, containers)
	}

	return nil
}

func (fw *flowWorker) finish() error {
	if err := fw.ctx.Err(); err != nil {
		if errors.Is(err, context.Canceled) {
			return nil

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the wrapped error and backend DB logs for the actual SQL failure
  2. Verify PostgreSQL connectivity and that the flows row still exists for the flow ID
  3. Retry the provider switch once connectivity is restored so the DB row is updated
  4. Reconcile by restarting the flow, which rebuilds the in-memory provider from the DB row

Example fix

// before: fire-and-forget switch can leave stale DB row
if err := fw.switchProvider(ctx, prv); err != nil {
    logger.Warn("switch failed, ignoring")
}
// after: surface and let caller retry / reconcile
if err := fw.switchProvider(ctx, prv); err != nil {
    return fmt.Errorf("provider switch incomplete for flow %d: %w", fw.flowCtx.FlowID, err)
}
Defensive patterns

Strategy: retry

Validate before calling

var exists int
if err := db.QueryRowContext(ctx, `SELECT COUNT(1) FROM flows WHERE id=$1`, flowID).Scan(&exists); err != nil || exists == 0 {
    return fmt.Errorf("flow %d not found; cannot update provider", flowID)
}

Type guard

func flowExists(ctx context.Context, db DB, id int64) bool {
    var n int
    _ = db.QueryRowContext(ctx, `SELECT COUNT(1) FROM flows WHERE id=$1`, id).Scan(&n)
    return n == 1
}

Try / catch

_, err := fw.flowCtx.DB.UpdateFlowProvider(ctx, params)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || isTransientDBError(err) {
        // retry with backoff
    }
    return fmt.Errorf("failed to update flow provider in DB: %w", err)
}

Prevention

When it happens

Trigger: UpdateFlowProvider returns an error when switching provider on a live flow — DB connection lost, context cancelled during the switch, the flow row was deleted concurrently, or a constraint/trigger on flows fails.

Common situations: PostgreSQL restart/pool exhaustion mid-switch; flow deleted by another operator while the switch was in flight; request context timed out; migration mismatch leaving flows table in an unexpected state.

Related errors


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