{"record":{"id":"69400ac1dcd7083e","repo":"plandex-ai/plandex","slug":"no-old-content-found-for-replacement","errorCode":null,"errorMessage":"no old content found for replacement","messagePattern":"no old content found for replacement","errorType":"validation","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/model/plan/build_validate_and_fix.go","lineNumber":380,"sourceCode":"\t\tlog.Printf(\"No replacements found in XML response\")\n\t\treturn buildValidateResult{\n\t\t\tvalid:   false,\n\t\t\tupdated: shared.RemoveLineNums(incremental),\n\t\t\tproblem: \"No replacements found in XML response\",\n\t\t}, nil\n\t}\n\n\treplacements := utils.GetAllXMLContent(replacementsOuter, \"Replacement\")\n\n\tfor i, replacement := range replacements {\n\t\tlog.Printf(\"Processing replacement: %d/%d\", i+1, len(replacements))\n\n\t\told := utils.GetXMLContent(replacement, \"Old\")\n\t\tnew := utils.GetXMLContent(replacement, \"New\")\n\n\t\tif old == \"\" {\n\t\t\tlog.Printf(\"No old content found for replacement\")\n\t\t\treturn buildValidateResult{valid: false, updated: updated}, fmt.Errorf(\"no old content found for replacement\")\n\t\t}\n\n\t\told = strings.TrimSpace(old)\n\n\t\t// log.Printf(\"Old content trimmed:\\n\\n%s\", strconv.Quote(old))\n\n\t\t// log.Printf(\"New content:\\n\\n%s\", strconv.Quote(new))\n\n\t\tif !strings.HasPrefix(old, \"pdx-\") {\n\t\t\tlog.Printf(\"Old content does not have a line number prefix for first line\")\n\t\t\treturn buildValidateResult{valid: false, updated: updated}, fmt.Errorf(\"old content does not have a line number prefix for first line\")\n\t\t}\n\n\t\toldLines := strings.Split(old, \"\\n\")\n\n\t\tvar lastLine string\n\t\tvar lastLineNum int\n\t\tfirstLine := oldLines[0]","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/build_validate_and_fix.go#L362-L398","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nold := utils.GetXMLContent(replacement, \"Old\")\nif old == \"\" {\n    return buildValidateResult{valid: false, updated: updated}, fmt.Errorf(\"no old content found for replacement\")\n}\n// after\nold := utils.GetXMLContent(replacement, \"Old\")\nif old == \"\" {\n    old = utils.GetXMLContent(replacement, \"old\") // tolerate case mismatch\n}\nif strings.TrimSpace(old) == \"\" {\n    return buildValidateResult{valid: false, updated: updated},\n        fmt.Errorf(\"no old content found for replacement %d\", i)\n}","handlingStrategy":"validation","validationCode":"// Validate the raw XML response before processing replacements\nfor i, replacement := range replacements {\n    if utils.GetXMLContent(replacement, \"Old\") == \"\" {\n        return fmt.Errorf(\"replacement %d missing Old content in model response\", i)\n    }\n}","typeGuard":"func hasValidOldContent(replacement string) bool {\n    old := utils.GetXMLContent(replacement, \"Old\")\n    if old == \"\" {\n        old = utils.GetXMLContent(replacement, \"old\")\n    }\n    return strings.TrimSpace(old) != \"\"\n}","tryCatchPattern":"old := utils.GetXMLContent(replacement, \"Old\")\nif strings.TrimSpace(old) == \"\" {\n    return buildValidateResult{valid: false, updated: updated},\n        fmt.Errorf(\"no old content found for replacement\")\n}","preventionTips":["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."],"tags":["xml-parsing","llm-output","validation"],"backgroundTag":"missing-required-xml-field","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}