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
- Strengthen the prompt/XML schema so every Replacement includes a non-empty <Old> block; show a correct example.
- Retry the attempt — buildValidateLoop will feed the problem back and re-run, and later attempts use the stronger model.
- Tolerate case differences by normalizing tag names (old/Old) in GetXMLContent before validation.
- 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
- Include explicit, complete Replacement XML examples (with non-empty Old) in the model prompt.
- Tolerate tag-name case variants and strip whitespace before the empty check.
- Set a max-token budget high enough to avoid truncated XML responses.
- Prefer stronger models for repair attempts, since weaker ones drop required fields.
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
- invalid line number for first line: %d
- invalid line numbers: %d-%d
- invalid context index: %s
- no context found with name: %s
- invalid value for --debug: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/69400ac1dcd7083e.
Report an issue: GitHub.