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
- Regenerate the plan/replacements for the failing path with the current file content as context
- Enable the commented debug logging (spew.Sdump of replacements and `updated`) to see why the replacement did not apply
- Verify the file content on disk/context matches the Sha captured in planState (re-capture if the file drifted)
- 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
- Re-capture context/Sha if the file changed after context creation
- Normalize whitespace/line endings between search text and file content
- Avoid overlapping replacements within the same file
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
- plan updates out of order: %s
- no context for path: %s
- connection to plan stream timed out due to missing heartbeat
- error loading accounts: %v
- error signing in to new account: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/335219644bbc14e5.
Report an issue: GitHub.