plandex-ai/plandex · error

plan replacement failed - %s

Error message

plan replacement failed - %s

What it means

During the replacement phase, the library attempted to apply search/replace edits to the file content for a path and the update did not produce content — the replacement operation failed for that path. The library aborts with the offending path so the caller knows which file's edits could not be applied.

Source

Thrown at app/shared/plan_result_replacements.go:253

				}

				// log.Println("Before replacements. updated:")
				// log.Println(updated)

				updated, allSucceeded = ApplyReplacements(maybeWithLineNums, replacements, false)

				updated = string(RemoveLineNums(LineNumberedTextType(updated)))

				if !allSucceeded {
					log.Println("Failed to apply replacements")

					// log.Println("replacements:")
					// log.Println(spew.Sdump(replacements))

					// log.Println("updated:")
					// log.Println(updated)

					return nil, fmt.Errorf("plan replacement failed - %s", path)
				}

				// log.Println("Updated content: ")
				// log.Println(updated)

				updatedAtByPath[path] = planRes.CreatedAt
			}

			if foundTarget {
				break PlanResLoop
			}
		}

		// log.Println("Setting updated content for path: ", path)

		files[path] = updated
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Regenerate the plan/replacements for the failing path with the current file content as context
  2. Enable the commented debug logging (spew.Sdump of replacements and `updated`) to see why the replacement did not apply
  3. Verify the file content on disk/context matches the Sha captured in planState (re-capture if the file drifted)
  4. Normalize whitespace/line endings between search text and file content
Defensive patterns

Strategy: try-catch

Validate before calling

func validateReplacementsApplicable(content string, replacements []shared.Replacement) error {
    for _, r := range replacements {
        if !strings.Contains(content, r.Search) {
            return fmt.Errorf("search text not found: %q", truncate(r.Search))
        }
    }
    return nil
}

Try / catch

files, err := GetFiles(results, state)
if err != nil {
    if strings.Contains(err.Error(), "plan replacement failed") {
        path := extractPath(err.Error())
        return fmt.Errorf("re-generate replacements for %s (content drifted or search text mismatch): %w", path, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling GetFiles when a plan result contains replacement sections that fail to match/apply against the current `updated` content for the path (e.g. search text not found, or replacements left the content empty/unchanged in an invalid way).

Common situations: LLM-generated search/replace blocks that don't exactly match the file (whitespace, stale line numbers); file content changed between context capture and replacement application; overlapping replacements in the same file.

Related errors


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