plandex-ai/plandex · error

error rejecting plan: %v

Error message

error rejecting plan: %v

What it means

RejectAllResults collects one value per spawned goroutine from errCh; any non-nil error is wrapped with this message and returned. It is the top-level failure of the reject-all operation — the inner error (panic, per-result failure) is nested inside.

Source

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

					errCh <- fmt.Errorf("panic in RejectAllResults: %v\n%s", r, debug.Stack())
					runtime.Goexit() // don't allow outer function to continue and double-send to channel
				}
			}()
			err := RejectPlanFile(orgId, planId, resultId, now)

			if err != nil {
				errCh <- fmt.Errorf("error rejecting result: %v", err)
				return
			}

			errCh <- nil
		}(resultId)
	}

	for i := 0; i < len(files); i++ {
		err := <-errCh
		if err != nil {
			return fmt.Errorf("error rejecting plan: %v", err)
		}
	}

	return nil
}

func DeletePendingResultsForPaths(orgId, planId string, paths map[string]bool) error {
	// log.Println("Deleting pending results for paths")
	resultsDir := getPlanResultsDir(orgId, planId)
	files, err := os.ReadDir(resultsDir)

	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}

		return fmt.Errorf("error reading results dir: %v", err)
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Unwrap the nested error to identify the failing resultId and its root cause
  2. Fix or remove the offending result file, then re-run RejectAllResults
  3. Stop concurrent ApplyPlan/RejectAllResults operations on the same plan (serialize with a lock)
  4. Add retry/skip semantics per result so one bad file doesn't abort the whole batch

Example fix

// before
for i := 0; i < len(files); i++ {
    err := <-errCh
    if err != nil {
        return fmt.Errorf("error rejecting plan: %v", err)
    }
}
// after: collect all failures instead of aborting at the first
var errs []error
for i := 0; i < len(files); i++ {
    if err := <-errCh; err != nil {
        errs = append(errs, err)
    }
}
if len(errs) > 0 {
    return fmt.Errorf("error rejecting plan (%d failures): %v", len(errs), errs[0])
}
Defensive patterns

Strategy: fallback

Validate before calling

if _, err := os.ReadDir(getPlanResultsDir(orgId, planId)); err != nil && !os.IsNotExist(err) {
    return fmt.Errorf("results dir unreadable before reject-all: %v", err)
}

Try / catch

var errs []error
for i := 0; i < len(files); i++ {
    if err := <-errCh; err != nil {
        errs = append(errs, err)
    }
}
if len(errs) > 0 {
    return fmt.Errorf("error rejecting plan: %d of %d failed: %v", len(errs), len(files), errors.Join(errs...))
}

Prevention

When it happens

Trigger: Any of the per-file goroutines sent a non-nil error (RejectPlanFile failure or recovered panic), causing the collect loop to abort on that receive. Note the loop returns early, so remaining goroutines' errors are abandoned but the buffered channel prevents leaks.

Common situations: First failing result masks the rest; bulk reject runs while an apply is concurrently rewriting the results dir; corrupt result files from an earlier crash make every run fail at the same item.

Related errors


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