plandex-ai/plandex · error

error storing convo message description: %v

Error message

error storing convo message description: %v

What it means

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.

Source

Thrown at app/server/db/result_helpers.go:615

		}(result)
	}

	for _, description := range convoMessageDescriptions {
		go func(description *ConvoMessageDescription) {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("panic in ApplyPlan: %v\n%s", r, debug.Stack())
					errCh <- fmt.Errorf("panic in ApplyPlan: %v\n%s", r, debug.Stack())
					runtime.Goexit() // don't allow outer function to continue and double-send to channel
				}
			}()
			description.AppliedAt = &now

			err := StoreDescription(description)

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

			errCh <- nil
		}(description)
	}

	if len(pendingNewFilesSet) > 0 {
		go func() {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("panic in ApplyPlan: %v\n%s", r, debug.Stack())
					errCh <- fmt.Errorf("panic in ApplyPlan: %v\n%s", r, debug.Stack())
					runtime.Goexit() // don't allow outer function to continue and double-send to channel
				}
			}()
			loadReq := shared.LoadContextRequest{}
			for path := range pendingNewFilesSet {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect the wrapped error for the underlying DB cause (connection refused, constraint name, timeout)
  2. Verify database connectivity and that the app's DB credentials/migrations are current
  3. If it is a duplicate-key error, make StoreDescription idempotent (upsert) or skip already-applied descriptions
  4. Retry the failed description(s) — the buffer-sized errCh means other items still completed
  5. Log description.Id with the error to correlate failures for re-apply

Example fix

// before
err := StoreDescription(description)
if err != nil {
    errCh <- fmt.Errorf("error storing convo message description: %v", err)
// after (idempotent store)
err := UpsertDescription(description) // ON CONFLICT (id) DO UPDATE
if err != nil {
    errCh <- fmt.Errorf("error storing convo message description %s: %w", description.Id, err)
Defensive patterns

Strategy: retry

Validate before calling

if err := db.PingContext(ctx); err != nil {
    return fmt.Errorf("database unreachable: %w", err)
}
if description == nil || description.Id == "" {
    return fmt.Errorf("invalid description")
}

Try / catch

err := <-errCh
if err != nil && strings.Contains(err.Error(), "error storing convo message description") {
    // parse wrapped DB error; retry transient failures with backoff
    var netErr net.Error
    if errors.As(err, &netErr) || errors.Is(err, sql.ErrConnDone) {
        // re-run ApplyPlan or re-store the failed description
    }
}

Prevention

When it happens

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

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

Related errors


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