{"record":{"id":"7786b94331f30d18","repo":"plandex-ai/plandex","slug":"error-storing-convo-message-description-v","errorCode":null,"errorMessage":"error storing convo message description: %v","messagePattern":"error storing convo message description: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/result_helpers.go","lineNumber":615,"sourceCode":"\n\t\t}(result)\n\t}\n\n\tfor _, description := range convoMessageDescriptions {\n\t\tgo func(description *ConvoMessageDescription) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tlog.Printf(\"panic in ApplyPlan: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\terrCh <- fmt.Errorf(\"panic in ApplyPlan: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\truntime.Goexit() // don't allow outer function to continue and double-send to channel\n\t\t\t\t}\n\t\t\t}()\n\t\t\tdescription.AppliedAt = &now\n\n\t\t\terr := StoreDescription(description)\n\n\t\t\tif err != nil {\n\t\t\t\terrCh <- fmt.Errorf(\"error storing convo message description: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\terrCh <- nil\n\t\t}(description)\n\t}\n\n\tif len(pendingNewFilesSet) > 0 {\n\t\tgo func() {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tlog.Printf(\"panic in ApplyPlan: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\terrCh <- fmt.Errorf(\"panic in ApplyPlan: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\truntime.Goexit() // don't allow outer function to continue and double-send to channel\n\t\t\t\t}\n\t\t\t}()\n\t\t\tloadReq := shared.LoadContextRequest{}\n\t\t\tfor path := range pendingNewFilesSet {","sourceCodeStart":597,"sourceCodeEnd":633,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/result_helpers.go#L597-L633","documentation":"ApplyPlan persists each ConvoMessageDescription via StoreDescription inside a goroutine. This error means StoreDescription returned a non-nil error; it is wrapped verbatim, so the database-layer cause (connection failure, constraint violation, timeout) is embedded in the message. The description is not applied and the goroutine reports the failure on errCh.","triggerScenarios":"StoreDescription(description) fails — e.g. the database is unreachable, the description violates a unique/FK constraint, the record is too large, a transaction times out, or a required field is empty and the store layer rejects it.","commonSituations":"DB connection pool exhausted or DB restarted mid-apply; re-applying the same plan causing duplicate-key violations; migration mismatch so the convo_message_descriptions table lacks an expected column; network partition between app and database.","solutions":["Inspect the wrapped error for the underlying DB cause (connection refused, constraint name, timeout)","Verify database connectivity and that the app's DB credentials/migrations are current","If it is a duplicate-key error, make StoreDescription idempotent (upsert) or skip already-applied descriptions","Retry the failed description(s) — the buffer-sized errCh means other items still completed","Log description.Id with the error to correlate failures for re-apply"],"exampleFix":"// before\nerr := StoreDescription(description)\nif err != nil {\n    errCh <- fmt.Errorf(\"error storing convo message description: %v\", err)\n// after (idempotent store)\nerr := UpsertDescription(description) // ON CONFLICT (id) DO UPDATE\nif err != nil {\n    errCh <- fmt.Errorf(\"error storing convo message description %s: %w\", description.Id, err)","handlingStrategy":"retry","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"database unreachable: %w\", err)\n}\nif description == nil || description.Id == \"\" {\n    return fmt.Errorf(\"invalid description\")\n}","typeGuard":null,"tryCatchPattern":"err := <-errCh\nif err != nil && strings.Contains(err.Error(), \"error storing convo message description\") {\n    // parse wrapped DB error; retry transient failures with backoff\n    var netErr net.Error\n    if errors.As(err, &netErr) || errors.Is(err, sql.ErrConnDone) {\n        // re-run ApplyPlan or re-store the failed description\n    }\n}","preventionTips":["Apply DB migrations before deploying; verify connection pool limits","Make StoreDescription idempotent (upsert) to survive plan re-application","Check errCh after ApplyPlan and re-apply failed descriptions","Monitor DB health; treat connection errors as transient and retryable"],"tags":["go","database","persistence","concurrency"],"backgroundTag":"database-write-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}