{"record":{"id":"e93b2ab6a6c48d8d","repo":"plandex-ai/plandex","slug":"error-getting-diff-replacements-v","errorCode":null,"errorMessage":"error getting diff replacements: %v","messagePattern":"error getting diff replacements: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/model/plan/build_structured_edits.go","lineNumber":199,"sourceCode":"\t\tPath:      filePath,\n\t\tNumTokens: 0,\n\t\tFinished:  true,\n\t}\n\tlog.Printf(\"streaming build info for finished file %s\\n\", filePath)\n\tactivePlan.Stream(shared.StreamMessage{\n\t\tType:      shared.StreamMessageBuildInfo,\n\t\tBuildInfo: buildInfo,\n\t})\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// strip any blank lines from beginning/end of updated file\n\tupdated = utils.StripAddedBlankLines(originalFile, updated)\n\n\tlog.Printf(\"buildStructuredEdits - %s - getting diff replacements\\n\", filePath)\n\treplacements, err := diff_pkg.GetDiffReplacements(originalFile, updated)\n\tif err != nil {\n\t\tlog.Printf(\"buildStructuredEdits - error getting diff replacements: %v\\n\", err)\n\t\tfileState.onBuildFileError(fmt.Errorf(\"error getting diff replacements: %v\", err))\n\t\treturn\n\t}\n\tlog.Printf(\"buildStructuredEdits - %s - got %d replacements\\n\", filePath, len(replacements))\n\n\tfor _, replacement := range replacements {\n\t\treplacement.Summary = strings.TrimSpace(desc)\n\t}\n\n\tres := db.PlanFileResult{\n\t\tTypeVersion:    1,\n\t\tOrgId:          fileState.plan.OrgId,\n\t\tPlanId:         fileState.plan.Id,\n\t\tPlanBuildId:    fileState.build.Id,\n\t\tConvoMessageId: fileState.convoMessageId,\n\t\tContent:        \"\",\n\t\tPath:           filePath,\n\t\tReplacements:   replacements,\n\t}","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/build_structured_edits.go#L181-L217","documentation":"After the updated file content is produced, buildStructuredEdits calls diff_pkg.GetDiffReplacements(originalFile, updated) to convert the whole-file diff into structured find/replace replacements. If that diff computation fails, the error is wrapped as \"error getting diff replacements: %v\" and reported through fileState.onBuildFileError, aborting the file build. This is a local diff-library failure, not an LLM failure.","triggerScenarios":"diff_pkg.GetDiffReplacements(originalFile, updated) returns a non-nil error, typically when the diff library cannot compute a valid line-based diff between the original and updated file contents (e.g. pathological content, encoding issues, or an internal diff algorithm error).","commonSituations":"LLM output mangled the file encoding (invalid UTF-8, mixed line endings) so the differ chokes; very large files exceeding diff-library limits; a version change in the diff package changing GetDiffReplacements' failure modes.","solutions":["Inspect the inner error; if it's an encoding/line-ending issue, normalize the updated content before diffing.","Check that utils.StripAddedBlankLines(originalFile, updated) is not producing content the differ can't handle (e.g. empty string).","Pin/upgrade the diff package version; check its issue tracker for known panics on large inputs.","Add a fallback that emits a whole-file replacement when the diff cannot be computed."],"exampleFix":"// before\nreplacements, err := diff_pkg.GetDiffReplacements(originalFile, updated)\nif err != nil {\n    fileState.onBuildFileError(fmt.Errorf(\"error getting diff replacements: %v\", err))\n    return\n}\n// after\nreplacements, err := diff_pkg.GetDiffReplacements(originalFile, updated)\nif err != nil {\n    log.Printf(\"diff failed (%v), falling back to whole-file replacement\", err)\n    replacements = []shared.Replacement{{Old: originalFile, New: updated}}\n}","handlingStrategy":"fallback","validationCode":"// Validate contents are diffable before calling\nif updated == \"\" || !utf8.ValidString(updated) || !utf8.ValidString(originalFile) {\n    return fmt.Errorf(\"cannot diff: invalid or empty content\")\n}","typeGuard":null,"tryCatchPattern":"replacements, err := diff_pkg.GetDiffReplacements(originalFile, updated)\nif err != nil {\n    log.Printf(\"GetDiffReplacements failed: %v; using whole-file replacement\", err)\n    replacements = []db.Replacement{{Old: originalFile, New: updated, Summary: strings.TrimSpace(desc)}}\n}","preventionTips":["Normalize line endings and encoding of LLM output before diffing.","Run StripAddedBlankLines and sanity-check the result is non-empty.","Pin the diff package version and add unit tests with large/pathological inputs.","Provide a whole-file-replacement fallback so builds degrade gracefully."],"tags":["diff","build-pipeline","error-wrapping"],"backgroundTag":"diff-computation-failed","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"}