plandex-ai/plandex · error

error storing convo message: %v

Error message

error storing convo message: %v

What it means

StorePartialReply persists the truncated assistant reply as a ConvoMessage via db.StoreConvoMessage. When that database write fails, the error is wrapped as "error storing convo message: %v" and returned. The underlying cause is whatever StoreConvoMessage hit — most commonly a database connectivity or constraint failure.

Source

Thrown at app/server/model/plan/stop.go:47

	if !active.BuildOnly && !active.RepliesFinished {
		num := active.MessageNum + 1

		userMsg := db.ConvoMessage{
			OrgId:   currentOrgId,
			PlanId:  planId,
			UserId:  currentUserId,
			Role:    openai.ChatMessageRoleAssistant,
			Tokens:  active.NumTokens,
			Num:     num,
			Stopped: true,
			Message: active.CurrentReplyContent,
		}

		_, err := db.StoreConvoMessage(repo, &userMsg, currentUserId, branch, true)

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

	return nil
}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect the wrapped inner error (everything after 'error storing convo message:') to identify the DB failure and fix that root cause.
  2. Verify database connectivity and health (connection limits, migrations) on the Plandex server host.
  3. Retry the stop/store operation once the DB is reachable — the partial reply is only persisted once.
  4. If the org/user referenced was deleted, clean up or recreate the account record before stopping plans tied to it.

Example fix

// before
if err := plan.StorePartialReply(repo, planId, branch, userId, orgId); err != nil {
    http.Error(w, err.Error(), 500)
}
// after
if err := plan.StorePartialReply(repo, planId, branch, userId, orgId); err != nil {
    log.Printf("store partial reply: %v", err) // read wrapped DB cause
    if !strings.Contains(err.Error(), "context canceled") {
        http.Error(w, "failed to save partial reply, see server logs", 500)
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if repo == nil || currentUserId == "" || currentOrgId == "" || planId == "" {
    return errors.New("cannot store partial reply: missing repo/org/user/plan identifiers")
}
// optionally ping DB before the write
if err := db.HealthCheck(); err != nil {
    return fmt.Errorf("db unavailable, will not store partial reply: %w", err)
}

Try / catch

if err := plan.StorePartialReply(repo, planId, branch, userId, orgId); err != nil {
    var inner error
    fmt.Sscanf(err.Error(), "error storing convo message: %v", &inner) // inspect wrapped cause
    log.Printf("partial reply store failed: %v", err)
    // do not lose the partial reply: retry once, then queue for later persistence
    return err
}

Prevention

When it happens

Trigger: db.StoreConvoMessage(repo, &userMsg, currentUserId, branch, true) returns a non-nil error while stopping a plan mid-reply: DB unreachable, transaction conflict, invalid org/user/plan id foreign keys, or a lock/timeout on the convo_messages table.

Common situations: Database down or connection pool exhausted under load; stopping a plan whose org/user ids no longer exist in the DB (user deleted mid-session); migration mismatch after an upgrade; disk-full or timeout on the DB host during a burst of stop requests.

Related errors


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