plandex-ai/plandex · warning

validation loop failed: %s

Error message

validation loop failed: %s

What it means

This error is raised when buildValidateLoop completes without error but reports the proposed content as invalid (validateResult.valid == false). The loop's human-readable reason for rejection (validateResult.problem) is included so the caller knows why the auto-apply edits did not validate.

Source

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

		fileState.builderRun.AutoApplyValidationFinishedAt = time.Now()

		if err != nil {
			if errors.Is(err, context.Canceled) {
				log.Printf("Context canceled during buildValidate")
				return
			}

			log.Printf("buildRace - validation loop failed: %v", err)
			sendErr(fmt.Errorf("error building validate loop: %w", err))
		} else {
			log.Printf("buildRace - validation loop finished, valid: %v", validateResult.valid)
			if validateResult.valid {
				log.Printf("buildRace - validation loop succeeded, valid: %v", validateResult.valid)
				sendRes(raceResult{content: validateResult.updated, valid: validateResult.valid})
			} else {
				log.Printf("buildRace - validation loop failed, valid: %v", validateResult.valid)
				sendErr(fmt.Errorf("validation loop failed: %s", validateResult.problem))
			}
		}
	}()

	errs := []error{}
	errChNumReceived := 0

	for {
		select {
		case <-buildCtx.Done():
			log.Printf("buildRace - context canceled")
			return raceResult{}, buildCtx.Err()
		case err := <-errCh:
			errChNumReceived++
			log.Printf("buildRace - error channel received %d: %v\n", errChNumReceived, err)

			if err != nil {
				errs = append(errs, err)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read validateResult.problem in the error text to see the specific rejection reason
  2. Retry the build so the model regenerates edits (this is a content problem, not infrastructure)
  3. Fall back to a whole-file build (buildRace already starts fallbacks, but a manual re-run with more context helps)
  4. Provide clearer desc/reasons context so the model produces applicable edits

Example fix

// before
res, err := fileState.buildRace(...)
applyEdits(res.content)
// after
res, err := fileState.buildRace(...)
if err != nil && strings.Contains(err.Error(), "validation loop failed") {
    log.Printf("proposed edits invalid, regenerating: %v", err)
    res, err = fileState.buildRace(...) // regenerate
}
applyEdits(res.content)
Defensive patterns

Strategy: fallback

Validate before calling

if validateResult == nil {
    return fmt.Errorf("no validation result produced")
}
if !validateResult.valid && validateResult.problem == "" {
    return fmt.Errorf("validation rejected edits without a reason")
}

Type guard

func isValidatedResult(r *buildValidateLoopResult) bool {
    return r != nil && r.valid && r.updated != ""
}

Try / catch

res, err := fileState.buildRace(...)
if err != nil {
    if strings.Contains(err.Error(), "validation loop failed:") {
        log.Printf("edits rejected: %s — falling back to whole-file build", err)
        return startWholeFileBuild("")
    }
    return err
}

Prevention

When it happens

Trigger: buildValidateLoop finishes successfully but its validation step rejects the proposed edits — validateResult.valid is false with a populated validateResult.problem (e.g. edits don't apply cleanly, syntax errors remain, or the LLM validator deems the result wrong).

Common situations: Model output produced edits that conflict with the current file, replacement markers didn't match, or residual syntax errors after applying the proposed changes during auto-apply.

Related errors


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