{"record":{"id":"51ce0f462e2ceb59","repo":"plandex-ai/plandex","slug":"error-storing-description-v","errorCode":null,"errorMessage":"error storing description: %v","messagePattern":"error storing description: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/model/plan/build_finish.go","lineNumber":112,"sourceCode":"\t\t\tConvoMessageDescriptions: planDescs,\n\t\t})\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error getting current plan state: %v\\n\", err)\n\t\t\treturn fmt.Errorf(\"error getting current plan state: %v\", err)\n\t\t}\n\n\t\tdescErrCh := make(chan error, len(unbuiltDescs))\n\t\tfor _, desc := range unbuiltDescs {\n\t\t\tif len(desc.Operations) > 0 {\n\t\t\t\tdesc.DidBuild = true\n\t\t\t\tdesc.BuildPathsInvalidated = map[string]bool{}\n\t\t\t}\n\n\t\t\tgo func(desc *db.ConvoMessageDescription) {\n\t\t\t\terr := db.StoreDescription(desc)\n\n\t\t\t\tif err != nil {\n\t\t\t\t\tdescErrCh <- fmt.Errorf(\"error storing description: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tdescErrCh <- nil\n\t\t\t}(desc)\n\t\t}\n\n\t\tfor range unbuiltDescs {\n\t\t\terr = <-descErrCh\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error storing description: %v\\n\", err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\terr = repo.GitAddAndCommit(branch, currentPlan.PendingChangesSummaryForBuild())\n\n\t\tif err != nil {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/build_finish.go#L94-L130","documentation":"Raised when db.StoreDescription(desc) fails inside the per-description goroutines that persist updated build flags for each unbuilt description. Errors are collected on descErrCh and the first one aborts the repo operation with 'error storing description: %v'. It means one of the ConvoMessageDescription updates (e.g. marking DidBuild=true, clearing BuildPathsInvalidated) could not be saved.","triggerScenarios":"After a build, for each unbuilt desc a goroutine calls db.StoreDescription(desc); the DB write fails (connection error, constraint violation, record deleted concurrently, context/transaction aborted) and the error is pushed to descErrCh and returned from the repo callback.","commonSituations":"DB connection pool exhaustion under many concurrent description stores; description row deleted by another process mid-build; unique/constraint violations from duplicate descriptions after a plan fork; Postgres restart during build finish.","solutions":["Inspect the wrapped err to identify the specific DB failure (connection vs constraint)","Retry the build finish; parallel store calls often succeed on a second attempt after a transient outage","Check for concurrent processes deleting or mutating description rows; serialize plan operations","Verify description rows exist and satisfy constraints (no duplicates from forks/imports)","Under sustained load, reduce concurrency or increase DB pool size"],"exampleFix":"// before: fire-and-forget goroutines can race with plan deletion\n// go func(desc *db.ConvoMessageDescription) { descErrCh <- ... }(desc)\n// after: check desc still valid before storing\nif desc != nil && desc.Id != \"\" {\n    go func(desc *db.ConvoMessageDescription) {\n        descErrCh <- db.StoreDescription(desc)\n    }(desc)\n}","handlingStrategy":"retry","validationCode":"if desc == nil || desc.Id == \"\" {\n    return fmt.Errorf(\"skipping invalid description before StoreDescription\")\n}","typeGuard":"func isStorableDescription(d *db.ConvoMessageDescription) bool {\n    return d != nil && d.Id != \"\" && d.OrgId != \"\" && d.PlanId != \"\"\n}","tryCatchPattern":"err := db.StoreDescription(desc)\nif err != nil {\n    descErrCh <- fmt.Errorf(\"error storing description: %w\", err)\n    return\n}\n// caller: retry the whole StoreDescription batch on transient DB errors","preventionTips":["Add bounded retries with backoff to StoreDescription for transient errors","Avoid deleting plan descriptions concurrently with an active build","Size the DB connection pool for the fan-out of parallel store goroutines","Use %w so errors.Is can distinguish constraint vs connection failures"],"tags":["go","database","concurrency","persistence"],"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"}