plandex-ai/plandex · error

error building validate loop: %v

Error message

error building validate loop: %v

What it means

This error wraps a panic recovered from the buildRace validation goroutine. When buildValidateLoop panics (nil dereference, index out of range, etc.), the deferred recover converts the panic value into an error and sends it on the error channel so the racing build can fail gracefully instead of crashing the process; runtime.Goexit then stops the goroutine to prevent a double-send.

Source

Thrown at app/server/model/plan/build_race.go:231

	onInitialStream := func(chunk string, buffer string) bool {
		if !startedFallbacks && strings.Contains(buffer, "<PlandexIncorrect/>") && strings.Contains(buffer, "<PlandexComments>") {
			log.Printf("buildRace - detected incorrect marker, triggering whole file build")

			comments := utils.GetXMLContent(buffer, "PlandexComments")

			startFallbacks(comments)
		}
		// keep streaming
		return false
	}

	fileState.builderRun.AutoApplyValidationStartedAt = time.Now()

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

		log.Printf("buildRace - starting validation loop")
		validateResult, err := fileState.buildValidateLoop(buildCtx, buildValidateLoopParams{
			originalFile:         originalFile,
			updated:              updated,
			proposedContent:      proposedContent,
			desc:                 desc,
			reasons:              reasons,
			syntaxErrors:         syntaxErrors,
			initialPhaseOnStream: onInitialStream,
			isInitial:            true,
			sessionId:            sessionId,
		})

		fileState.builderRun.AutoApplyValidationFinishedAt = time.Now()

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the panic stack in the server log ('panic in buildRace validation loop') to find the exact nil/panic site in buildValidateLoop
  2. Add nil/empty checks at the top of buildValidateLoop for proposedContent, updated, and originalFile before processing
  3. Ensure fileState and fileState.builderRun are fully initialized before calling buildRace
  4. Guard concurrent access to fileState fields shared with other build goroutines with a mutex or send immutable copies

Example fix

// before
lines := strings.Split(proposedContent, "\n")
edit := lines[editStart-1]
// after
lines := strings.Split(proposedContent, "\n")
if editStart < 1 || editStart > len(lines) {
    return buildValidateLoopResult{}, fmt.Errorf("edit start %d out of range (file has %d lines)", editStart, len(lines))
}
edit := lines[editStart-1]
Defensive patterns

Strategy: try-catch

Validate before calling

if proposedContent == "" || fileState == nil || fileState.builderRun == nil {
    return fmt.Errorf("precondition failed: empty proposed content or uninitialized fileState")
}

Type guard

func safeIndex(s string, i int) (byte, bool) {
    if i < 0 || i >= len(s) { return 0, false }
    return s[i], true
}

Try / catch

// in the goroutine, wrap the whole loop body; the library already does this:
go func() {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("panic in validation loop: %v\n%s", r, debug.Stack())
            sendErr(fmt.Errorf("error building validate loop: %v", r))
            runtime.Goexit()
        }
    }()
    // ... buildValidateLoop ...
}()

Prevention

When it happens

Trigger: A runtime panic inside fileState.buildValidateLoop while it validates/applies proposed edits — e.g. nil map/slice access on proposed content, out-of-range index on file lines, or a nil pointer on a builderRun/fileState field during auto-apply validation.

Common situations: Proposed content has unexpected structure (empty file, malformed markers), a tree-sitter parse returns nil nodes that are dereferenced, or concurrent mutation of fileState fields while the validation goroutine reads them.

Related errors


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