{"record":{"id":"b05e6a696f88eb02","repo":"vxcontrol/pentagi","slug":"failed-to-rename-flow-d-w","errorCode":null,"errorMessage":"failed to rename flow %d: %w","messagePattern":"failed to rename flow (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/flow.go","lineNumber":858,"sourceCode":"\t}()\n\n\tselect {\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"task stop timeout\")\n\tcase <-done:\n\t\treturn nil\n\t}\n}\n\nfunc (fw *flowWorker) Rename(ctx context.Context, title string) error {\n\tfw.flowCtx.Provider.SetTitle(title)\n\n\tflow, err := fw.flowCtx.DB.UpdateFlowTitle(ctx, database.UpdateFlowTitleParams{\n\t\tID:    fw.flowCtx.FlowID,\n\t\tTitle: title,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to rename flow %d: %w\", fw.flowCtx.FlowID, err)\n\t}\n\n\tcontainers, err := fw.flowCtx.DB.GetFlowContainers(ctx, fw.flowCtx.FlowID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get flow %d containers: %w\", fw.flowCtx.FlowID, err)\n\t}\n\n\tfw.flowCtx.Publisher.FlowUpdated(ctx, flow, containers)\n\n\treturn nil\n}\n\n// switchProvider performs runtime provider switch for the flow.\n//\n// This is the single place where a running flow picks up a provider change. A\n// rename or deletion of a user provider only rewrites the DB reference (see\n// flowController.reassignFlowsProvider); the in-memory instance is refreshed\n// here, on the next user input, or rebuilt from the DB row on the next start.","sourceCodeStart":840,"sourceCodeEnd":876,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/flow.go#L840-L876","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped DB error; for 'no rows', treat as 'flow not found' and inform the user rather than retrying blindly.","Verify DB connectivity and pool configuration; retry after transient failures.","Run pending goose migrations so the flows schema matches the queries.","Pass a ctx with sufficient deadline for the UPDATE to complete."],"exampleFix":"// before\nflow, err := db.UpdateFlowTitle(ctx, params) // ctx cancelled by 1s HTTP timeout\n// after\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\ndefer cancel()\nflow, err := db.UpdateFlowTitle(ctx, params)","handlingStrategy":"validation","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"db unreachable before rename: %w\", err)\n}\nif err := ctx.Err(); err != nil {\n    return fmt.Errorf(\"ctx done before rename: %w\", err)\n}","typeGuard":"func isFlowNotFound(err error) bool {\n    return errors.Is(err, sql.ErrNoRows)\n}","tryCatchPattern":"if err := worker.Rename(ctx, title); err != nil {\n    if isFlowNotFound(errors.Unwrap(errors.Unwrap(err))) {\n        return ErrFlowNotFound // flow deleted concurrently; don't retry\n    }\n    if isTransientDBErr(err) {\n        return retryWithBackoff(3, func() error { return worker.Rename(ctx, title) })\n    }\n    return err\n}","preventionTips":["Validate the flow still exists before renaming (avoid races with concurrent deletes).","Give rename requests an adequate DB deadline.","Keep goose migrations current for the flows table.","Make rename idempotent: renaming to the same title should succeed."],"tags":["go","database","postgres","update"],"backgroundTag":"database-update-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}