plandex-ai/plandex · error

error storing description: %v

Error message

error storing description: %v

What it means

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.

Source

Thrown at app/server/model/plan/build_finish.go:112

			ConvoMessageDescriptions: planDescs,
		})
		if err != nil {
			log.Printf("Error getting current plan state: %v\n", err)
			return fmt.Errorf("error getting current plan state: %v", err)
		}

		descErrCh := make(chan error, len(unbuiltDescs))
		for _, desc := range unbuiltDescs {
			if len(desc.Operations) > 0 {
				desc.DidBuild = true
				desc.BuildPathsInvalidated = map[string]bool{}
			}

			go func(desc *db.ConvoMessageDescription) {
				err := db.StoreDescription(desc)

				if err != nil {
					descErrCh <- fmt.Errorf("error storing description: %v", err)
					return
				}

				descErrCh <- nil
			}(desc)
		}

		for range unbuiltDescs {
			err = <-descErrCh
			if err != nil {
				log.Printf("Error storing description: %v\n", err)
				return err
			}
		}

		err = repo.GitAddAndCommit(branch, currentPlan.PendingChangesSummaryForBuild())

		if err != nil {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect the wrapped err to identify the specific DB failure (connection vs constraint)
  2. Retry the build finish; parallel store calls often succeed on a second attempt after a transient outage
  3. Check for concurrent processes deleting or mutating description rows; serialize plan operations
  4. Verify description rows exist and satisfy constraints (no duplicates from forks/imports)
  5. Under sustained load, reduce concurrency or increase DB pool size

Example fix

// before: fire-and-forget goroutines can race with plan deletion
// go func(desc *db.ConvoMessageDescription) { descErrCh <- ... }(desc)
// after: check desc still valid before storing
if desc != nil && desc.Id != "" {
    go func(desc *db.ConvoMessageDescription) {
        descErrCh <- db.StoreDescription(desc)
    }(desc)
}
Defensive patterns

Strategy: retry

Validate before calling

if desc == nil || desc.Id == "" {
    return fmt.Errorf("skipping invalid description before StoreDescription")
}

Type guard

func isStorableDescription(d *db.ConvoMessageDescription) bool {
    return d != nil && d.Id != "" && d.OrgId != "" && d.PlanId != ""
}

Try / catch

err := db.StoreDescription(desc)
if err != nil {
    descErrCh <- fmt.Errorf("error storing description: %w", err)
    return
}
// caller: retry the whole StoreDescription batch on transient DB errors

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/51ce0f462e2ceb59. Report an issue: GitHub.