{"record":{"id":"3831c3c21192e934","repo":"vxcontrol/pentagi","slug":"failed-to-create-flow-in-db-w","errorCode":null,"errorMessage":"failed to create flow in DB: %w","messagePattern":"failed to create flow in DB: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"backend/pkg/controller/flow.go","lineNumber":145,"sourceCode":"\tfwc newFlowWorkerCtx,\n) (_ FlowWorker, err error) {\n\tctx, span := obs.Observer.NewSpan(ctx, obs.SpanKindInternal, \"controller.NewFlowWorker\")\n\tdefer span.End()\n\n\tflow, err := fwc.db.CreateFlow(ctx, database.CreateFlowParams{\n\t\tTitle:              \"untitled\",\n\t\tStatus:             database.FlowStatusCreated,\n\t\tModel:              \"unknown\",\n\t\tModelProviderName:  fwc.prvname.String(),\n\t\tModelProviderType:  database.ProviderType(fwc.prvtype),\n\t\tLanguage:           \"English\",\n\t\tToolCallIDTemplate: cast.ToolCallIDTemplate,\n\t\tFunctions:          []byte(\"{}\"),\n\t\tUserID:             fwc.userID,\n\t})\n\tif err != nil {\n\t\tobs.LogErrorOrCancel(logrus.WithContext(ctx), err, \"failed to create flow in DB\")\n\t\treturn nil, fmt.Errorf(\"failed to create flow in DB: %w\", err)\n\t}\n\n\tlogger := logrus.WithContext(ctx).WithFields(logrus.Fields{\n\t\t\"flow_id\":       flow.ID,\n\t\t\"user_id\":       fwc.userID,\n\t\t\"provider_name\": fwc.prvname.String(),\n\t\t\"provider_type\": fwc.prvtype.String(),\n\t})\n\tlogger.Info(\"flow created in DB\")\n\n\t// Held separately because `flow` is reassigned below by UpdateFlow, which — like every sqlc query —\n\t// returns a zero-valued row alongside an error, and a cleanup aimed at id 0 deletes nothing.\n\tflowID := flow.ID\n\n\t// DeleteFlow is a soft delete and the listings filter on deleted_at, so this is what keeps a flow\n\t// the caller was told it never got out of the UI. Disarmed once the worker goroutine owns the flow —\n\t// from there a failure is the worker's to unwind, not ours.\n\tcleanupFlow := true","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/flow.go#L127-L163","documentation":"NewFlowWorker creates the flow row via db.CreateFlow before anything else; if the insert fails the worker cannot exist, so it logs via obs.LogErrorOrCancel and wraps the DB error with 'failed to create flow in DB'. The wrapped error carries the underlying database/SQLC cause (connection failure, constraint violation, context cancellation).","triggerScenarios":"db.CreateFlow returns an error: database unreachable/down, migration missing tables, context cancelled by the client while inserting, invalid UserID foreign key, or connection pool exhaustion.","commonSituations":"Postgres container stopped or misconfigured DB host/port in .env; client disconnected mid-request cancelling ctx; FK violation because the user was deleted concurrently; DB pool exhausted under load.","solutions":["Check PostgreSQL is reachable and credentials (POSTGRES_* env vars) are correct.","Inspect the wrapped %w cause in logs for the specific SQL error (connection refused vs constraint vs cancel).","Run goose migrations to ensure the flows table and enums exist.","If the cause is context cancellation, keep the HTTP request alive long enough or use context.WithoutCancel for startup inserts.","Check connection pool limits if the error appears only under high concurrency."],"exampleFix":"// before\nctx := r.Context() // cancelled when client disconnects, aborting insert\nflow, err := controller.NewFlowWorker(ctx, fwc)\n// after\nctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)\ndefer cancel()\nflow, err := controller.NewFlowWorker(ctx, fwc)\nif err != nil {\n    log.WithError(errors.Unwrap(err)).Error(\"flow creation failed\") // inspect root cause\n}","handlingStrategy":"try-catch","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"database unreachable: %w\", err)\n}\nif userID <= 0 { return errors.New(\"valid userID required\") }","typeGuard":null,"tryCatchPattern":"fw, err := controller.NewFlowWorker(ctx, fwc)\nif err != nil {\n    var root = errors.Unwrap(err)\n    if errors.Is(root, context.Canceled) { /* client gone: no retry */ }\n    else { /* transient DB issue: retry with backoff */ }\n    log.WithError(root).Error(\"flow creation failed\")\n}","preventionTips":["Monitor Postgres connectivity before accepting flow-creation requests","Keep request contexts alive at least as long as the insert; use WithoutCancel for cleanup","Run goose migrations on deploy so the flows schema always exists","Size the DB connection pool for peak flow-creation concurrency"],"tags":["go","database","postgres","flow-creation"],"backgroundTag":"database-insert-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}