{"record":{"id":"c62087d3d76d16e1","repo":"charmbracelet/crush","slug":"old-string-appears-multiple-times-in-the-file-ple","errorCode":null,"errorMessage":"old_string appears multiple times in the file. Please provide more context to ensure a unique match, or set replace_all to true","messagePattern":"old_string appears multiple times in the file\\. Please provide more context to ensure a unique match, or set replace_all to true","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/edit.go","lineNumber":212,"sourceCode":"\n// findAndReplace performs a find-and-replace on content. When replaceAll is\n// false it requires exactly one match. If an exact match fails, it falls back\n// to whitespace-normalized matching and, failing that, returns a diagnostic\n// hint describing why the replacement could not be made. The returned boolean\n// reports whether the replacement relied on the whitespace-normalized\n// fallback rather than an exact match.\nfunc findAndReplace(content, old, new string, replaceAll bool) (string, bool, error) {\n\tif replaceAll {\n\t\tif strings.Contains(content, old) {\n\t\t\treturn strings.ReplaceAll(content, old, new), false, nil\n\t\t}\n\t} else {\n\t\tindex := strings.Index(content, old)\n\t\tswitch {\n\t\tcase index == -1:\n\t\t\t// Fall through to the fuzzy fallback below.\n\t\tcase index != strings.LastIndex(content, old):\n\t\t\treturn \"\", false, fmt.Errorf(\"old_string appears multiple times in the file. Please provide more context to ensure a unique match, or set replace_all to true\")\n\t\tdefault:\n\t\t\treturn content[:index] + new + content[index+len(old):], false, nil\n\t\t}\n\t}\n\n\tif result, ok := normalizedReplace(content, old, new, replaceAll); ok {\n\t\treturn result, true, nil\n\t}\n\treturn \"\", false, notFoundError(content, old)\n}\n\n// withWhitespaceNote appends the whitespace auto-correction note to a tool\n// response message when the edit did not match the file byte-for-byte.\nfunc withWhitespaceNote(message string, whitespaceCorrected bool) string {\n\tif !whitespaceCorrected {\n\t\treturn message\n\t}\n\treturn message + \"\\n\" + whitespaceCorrectedNote","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/edit.go#L194-L230","documentation":"findAndReplace requires old_string to occur exactly once in the file when replace_all is false. If strings.Index and strings.LastIndex disagree, the string occurs multiple times and this guard rejects the edit rather than making an ambiguous replacement. It is a deliberate safety check against unintended mass edits.","triggerScenarios":"Calling the edit tool with an old_string that matches 2+ locations in the file while replace_all is false — typically because the snippet is too short or generic (e.g. a closing brace, a repeated import line, an identifier alone on a line).","commonSituations":"Model-supplied edits using short common snippets, refactors where the same pattern appears in several functions, CRLF vs LF mismatches after whitespace normalization changing match counts.","solutions":["Expand old_string to include surrounding unique context (more lines, distinctive tokens).","Set replace_all to true if every occurrence should be replaced.","Split the edit into multiple calls, each targeting one unique occurrence.","Re-read the file (View tool) to copy exact text including indentation, then retry."],"exampleFix":"// before\n{\"old_string\": \"return nil\", \"new_string\": \"return err\"}\n// after: include unique context\n{\"old_string\": \"if err != nil {\\n\\treturn nil\\n}\", \"new_string\": \"if err != nil {\\n\\treturn err\\n}\", \"replace_all\": false}","handlingStrategy":"validation","validationCode":"func isUniqueEnough(content, old string) bool {\n\tif strings.Count(content, old) != 1 {\n\t\treturn false\n\t}\n\treturn true\n}\n// gate the tool call:\n// if !isUniqueEnough(fileContent, oldString) { set replace_all or extend context }","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"appears multiple times\") {\n\t// widen old_string with surrounding lines, or set replace_all: true, and retry\n}","preventionTips":["Include 2-3 lines of surrounding context in old_string, not one-liners.","Never use bare braces, imports, or identifiers as old_string.","Copy old_string verbatim from a fresh View of the file.","Set replace_all:true deliberately when replacing every occurrence."],"tags":["string-match","ambiguity","edit-tool","validation"],"backgroundTag":"ambiguous-string-match","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}