vxcontrol/pentagi · error

failed to rename flow %d: %w

Error message

failed to rename flow %d: %w

What it means

Rename wraps the error from fw.flowCtx.DB.UpdateFlowTitle — the SQL update of the flow's title row failed, so the rename did not persist and the FlowUpdated event is not emitted. The wrapped error carries the underlying database cause.

Source

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

	}()

	select {
	case <-timer.C:
		return fmt.Errorf("task stop timeout")
	case <-done:
		return nil
	}
}

func (fw *flowWorker) Rename(ctx context.Context, title string) error {
	fw.flowCtx.Provider.SetTitle(title)

	flow, err := fw.flowCtx.DB.UpdateFlowTitle(ctx, database.UpdateFlowTitleParams{
		ID:    fw.flowCtx.FlowID,
		Title: title,
	})
	if err != nil {
		return fmt.Errorf("failed to rename flow %d: %w", fw.flowCtx.FlowID, err)
	}

	containers, err := fw.flowCtx.DB.GetFlowContainers(ctx, fw.flowCtx.FlowID)
	if err != nil {
		return fmt.Errorf("failed to get flow %d containers: %w", fw.flowCtx.FlowID, err)
	}

	fw.flowCtx.Publisher.FlowUpdated(ctx, flow, containers)

	return nil
}

// switchProvider performs runtime provider switch for the flow.
//
// This is the single place where a running flow picks up a provider change. A
// rename or deletion of a user provider only rewrites the DB reference (see
// flowController.reassignFlowsProvider); the in-memory instance is refreshed
// here, on the next user input, or rebuilt from the DB row on the next start.

View on GitHub (pinned to ea665308ba)

Solutions

  1. Inspect the wrapped DB error; for 'no rows', treat as 'flow not found' and inform the user rather than retrying blindly.
  2. Verify DB connectivity and pool configuration; retry after transient failures.
  3. Run pending goose migrations so the flows schema matches the queries.
  4. Pass a ctx with sufficient deadline for the UPDATE to complete.

Example fix

// before
flow, err := db.UpdateFlowTitle(ctx, params) // ctx cancelled by 1s HTTP timeout
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
flow, err := db.UpdateFlowTitle(ctx, params)
Defensive patterns

Strategy: validation

Validate before calling

if err := db.PingContext(ctx); err != nil {
    return fmt.Errorf("db unreachable before rename: %w", err)
}
if err := ctx.Err(); err != nil {
    return fmt.Errorf("ctx done before rename: %w", err)
}

Type guard

func isFlowNotFound(err error) bool {
    return errors.Is(err, sql.ErrNoRows)
}

Try / catch

if err := worker.Rename(ctx, title); err != nil {
    if isFlowNotFound(errors.Unwrap(errors.Unwrap(err))) {
        return ErrFlowNotFound // flow deleted concurrently; don't retry
    }
    if isTransientDBErr(err) {
        return retryWithBackoff(3, func() error { return worker.Rename(ctx, title) })
    }
    return err
}

Prevention

When it happens

Trigger: Calling Rename(ctx, title) when UpdateFlowTitle fails: DB unreachable, flow row deleted concurrently (no rows affected / not found), permission issue on the table, or ctx cancelled during the UPDATE.

Common situations: User renames a flow that another tab/session just deleted; PostgreSQL connection pool exhausted; migration drift missing a column; request ctx times out during the update under load.

Related errors


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