plandex-ai/plandex · error

no old content found for replacement

Error message

no old content found for replacement

What it means

When parsing the model's XML response in handleXMLResponse, each <Replacement> block must contain non-empty <Old> content identifying the text to replace. If utils.GetXMLContent(replacement, "Old") returns an empty string, buildValidate returns valid=false with the error "no old content found for replacement". This guards against model output that omits the required Old field, which would otherwise cause ambiguous or no-op replacements.

Source

Thrown at app/server/model/plan/build_validate_and_fix.go:380

		log.Printf("No replacements found in XML response")
		return buildValidateResult{
			valid:   false,
			updated: shared.RemoveLineNums(incremental),
			problem: "No replacements found in XML response",
		}, nil
	}

	replacements := utils.GetAllXMLContent(replacementsOuter, "Replacement")

	for i, replacement := range replacements {
		log.Printf("Processing replacement: %d/%d", i+1, len(replacements))

		old := utils.GetXMLContent(replacement, "Old")
		new := utils.GetXMLContent(replacement, "New")

		if old == "" {
			log.Printf("No old content found for replacement")
			return buildValidateResult{valid: false, updated: updated}, fmt.Errorf("no old content found for replacement")
		}

		old = strings.TrimSpace(old)

		// log.Printf("Old content trimmed:\n\n%s", strconv.Quote(old))

		// log.Printf("New content:\n\n%s", strconv.Quote(new))

		if !strings.HasPrefix(old, "pdx-") {
			log.Printf("Old content does not have a line number prefix for first line")
			return buildValidateResult{valid: false, updated: updated}, fmt.Errorf("old content does not have a line number prefix for first line")
		}

		oldLines := strings.Split(old, "\n")

		var lastLine string
		var lastLineNum int
		firstLine := oldLines[0]

View on GitHub (pinned to e2d772072e)

Solutions

  1. Strengthen the prompt/XML schema so every Replacement includes a non-empty <Old> block; show a correct example.
  2. Retry the attempt — buildValidateLoop will feed the problem back and re-run, and later attempts use the stronger model.
  3. Tolerate case differences by normalizing tag names (old/Old) in GetXMLContent before validation.
  4. Increase the max output token budget for the validation call to avoid truncated XML.

Example fix

// before
old := utils.GetXMLContent(replacement, "Old")
if old == "" {
    return buildValidateResult{valid: false, updated: updated}, fmt.Errorf("no old content found for replacement")
}
// after
old := utils.GetXMLContent(replacement, "Old")
if old == "" {
    old = utils.GetXMLContent(replacement, "old") // tolerate case mismatch
}
if strings.TrimSpace(old) == "" {
    return buildValidateResult{valid: false, updated: updated},
        fmt.Errorf("no old content found for replacement %d", i)
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the raw XML response before processing replacements
for i, replacement := range replacements {
    if utils.GetXMLContent(replacement, "Old") == "" {
        return fmt.Errorf("replacement %d missing Old content in model response", i)
    }
}

Type guard

func hasValidOldContent(replacement string) bool {
    old := utils.GetXMLContent(replacement, "Old")
    if old == "" {
        old = utils.GetXMLContent(replacement, "old")
    }
    return strings.TrimSpace(old) != ""
}

Try / catch

old := utils.GetXMLContent(replacement, "Old")
if strings.TrimSpace(old) == "" {
    return buildValidateResult{valid: false, updated: updated},
        fmt.Errorf("no old content found for replacement")
}

Prevention

When it happens

Trigger: The LLM validation/repair response contains a <Replacement> element whose <Old> child is missing or empty — e.g. the model emitted only <New>, wrapped Old in a different tag name, used CDATA/escaping the parser doesn't handle, or produced a truncated response.

Common situations: Weaker models (used on early attempts) omitting required XML fields; response truncation from max-tokens limits; tag-name casing mismatches (<old> vs <Old>); prompts whose examples don't enforce the Old field.

Related errors


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