plandex-ai/plandex · error

error storing user message: %v

Error message

error storing user message: %v

What it means

This error is produced by the storeUserMessage goroutine's recover handler: the goroutine that persists the user's prompt message panicked. The panic value is wrapped and sent on innerErrCh so loadTellPlan aborts instead of crashing the process.

Source

Thrown at app/server/model/plan/tell_load.go:198

			res, err := db.GetPlanConvo(currentOrgId, planId)
			if err != nil {
				log.Printf("Error getting plan convo: %v\n", err)
				errCh <- fmt.Errorf("error getting plan convo: %v", err)
				return
			}
			convo = res
			UpdateActivePlan(planId, branch, func(ap *types.ActivePlan) {
				ap.MessageNum = len(convo)
			})

			promptTokens := shared.GetNumTokensEstimate(req.Prompt)
			innerErrCh := make(chan error, 2)

			go func() {
				defer func() {
					if r := recover(); r != nil {
						log.Printf("panic in storeUserMessage: %v\n%s", r, debug.Stack())
						innerErrCh <- fmt.Errorf("error storing user message: %v", r)
						runtime.Goexit() // don't allow outer function to continue and double-send to channel
					}
				}()

				if iteration == 0 && missingFileResponse == "" && !req.IsUserContinue {
					num := len(convo) + 1

					log.Printf("[TellLoad] storing user message | len(convo): %d | num: %d\n", len(convo), num)

					promptMsg = &db.ConvoMessage{
						OrgId:   currentOrgId,
						PlanId:  planId,
						UserId:  currentUserId,
						Role:    openai.ChatMessageRoleUser,
						Tokens:  promptTokens,
						Num:     num,
						Message: req.Prompt,
						Flags: shared.ConvoMessageFlags{

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect the 'panic in storeUserMessage' log stack trace to pinpoint the deref site
  2. Ensure the repo (git repo wrapper) is successfully opened and non-nil before starting the goroutine
  3. Validate auth.User and currentUserId are set before calling loadTellPlan
  4. Guard UpdateActivePlan against a missing active plan entry for planId/branch
  5. Run with -race to detect concurrent access to the active plan or repo

Example fix

// before
_, err = db.StoreConvoMessage(repo, promptMsg, auth.User.Id, branch, true)
// after
if repo == nil || auth == nil || auth.User == nil {
    innerErrCh <- fmt.Errorf("error storing user message: nil repo or user")
    return
}
_, err = db.StoreConvoMessage(repo, promptMsg, auth.User.Id, branch, true)
Defensive patterns

Strategy: validation

Validate before calling

if repo == nil {
    return fmt.Errorf("git repo not initialized; cannot store user message")
}
if auth == nil || auth.User == nil || auth.User.Id == "" {
    return fmt.Errorf("authenticated user required to store user message")
}

Type guard

func canStoreUserMessage(repo *git.Repository, auth *auth.Session) bool {
    return repo != nil && auth != nil && auth.User != nil && auth.User.Id != ""
}

Try / catch

if err := <-innerErrCh; err != nil && strings.HasPrefix(err.Error(), "error storing user message:") {
    // recovered panic path — inspect stack trace already logged, abort plan load
    return err
}

Prevention

When it happens

Trigger: A panic inside the goroutine guarded at tell_load.go:198 — e.g., nil repo pointer, nil promptMsg construction failure, nil map access while building the db.ConvoMessage, or a panic inside db.StoreConvoMessage or UpdateActivePlan during the first iteration (iteration==0, no missingFileResponse, not IsUserContinue).

Common situations: Git repo wrapper (repo) is nil because the repository failed to load or was closed concurrently; active plan record was deleted mid-request causing nil deref in UpdateActivePlan; nil auth.User or currentUserId from a stale session.

Related errors


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