{"record":{"id":"4d47e15ebb1fe297","repo":"can1357/oh-my-pi","slug":"found-occurrences-occurrences-pathsuffix-mor","errorCode":null,"errorMessage":"Found ${occurrences} occurrences${pathSuffix}${moreMsg}:\\n\\n${previews}\\n\\nAdd more context lines to disambiguate.","messagePattern":"Found (.+?) occurrences(.+?)(.+?):\\\\n\\\\n(.+?)\\\\n\\\\nAdd more context lines to disambiguate\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/diff.ts","lineNumber":917,"sourceCode":"\t\treplacements.sort((a, b) => a.startIndex - b.startIndex);\n\t\tconst parts: string[] = [];\n\t\tlet sourceIndex = 0;\n\t\tfor (const replacement of replacements) {\n\t\t\tparts.push(normalizedContent.substring(sourceIndex, replacement.startIndex), replacement.text);\n\t\t\tsourceIndex = replacement.endIndex;\n\t\t}\n\t\tparts.push(normalizedContent.substring(sourceIndex));\n\t\treturn { content: parts.join(\"\"), count: replacements.length };\n\t}\n\n\t// Single replacement mode\n\tconst matchOutcome = findMatch(normalizedContent, normalizedOldText, {\n\t\tallowFuzzy: options.fuzzy,\n\t\tthreshold,\n\t});\n\n\tif (matchOutcome.occurrences && matchOutcome.occurrences > 1) {\n\t\tthrow new Error(formatOccurrenceMatchError(matchOutcome.occurrences, matchOutcome.occurrencePreviews));\n\t}\n\n\tif (!matchOutcome.match) {\n\t\treturn { content: normalizedContent, count: 0 };\n\t}\n\n\tconst match = matchOutcome.match;\n\tconst adjustedNewText = adjustIndentation(normalizedOldText, match.actualText, normalizedNewText);\n\tnormalizedContent =\n\t\tnormalizedContent.substring(0, match.startIndex) +\n\t\tadjustedNewText +\n\t\tnormalizedContent.substring(match.startIndex + match.actualText.length);\n\n\treturn { content: normalizedContent, count: 1 };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Preview/Diff Computation","sourceCodeStart":899,"sourceCodeEnd":935,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/diff.ts#L899-L935","documentation":"When findMatch() locates more than one occurrence of oldText in the (LF-normalized) content, replaceText() refuses to guess which one to replace and throws a formatted error listing the occurrence count, per-occurrence previews, and the file path. The library requires unambiguous matches; the caller must add more surrounding context lines to make oldText unique.","triggerScenarios":"Calling replaceText (or the edit tool backed by it) with oldText that appears 2+ times in the target file, e.g. a short snippet, a repeated import line, or a duplicated function stub; also when options.fuzzy lets near-identical regions both pass the threshold.","commonSituations":"Editing repeated YAML/JSON keys, duplicated boilerplate (empty catch blocks, repeated log lines), or agents editing files with copy-pasted sections like two identical test cases or config blocks.","solutions":["Expand oldText with more surrounding lines (unique imports, distinctive comments, neighboring identifiers) until it matches exactly one location.","Include line-number/hashline anchors via the hashline edit format instead of a plain text match.","If replacing ALL occurrences is intended, loop with a replace-all API rather than single replaceText."],"exampleFix":"// before\nreplaceText(content, 'return null;', 'return undefined;', { fuzzy: false });\n// after\nreplaceText(\n  content,\n  'function findUser(id: string) {\\n  return null;\\n}',\n  'function findUser(id: string) {\\n  return undefined;\\n}',\n  { fuzzy: false }\n);","handlingStrategy":"validation","validationCode":"const occurrences = content.split(oldText).length - 1;\nif (occurrences !== 1) {\n  throw new Error(`oldText matches ${occurrences} times; add context to disambiguate`);\n}\nconst result = replaceText(content, oldText, newText, options);","typeGuard":null,"tryCatchPattern":"try {\n  return replaceText(content, oldText, newText, { fuzzy: false });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('occurrences')) {\n    // retry with expanded context derived from occurrence previews in e.message\n    return replaceTextWithMoreContext(content, oldText, newText);\n  }\n  throw e;\n}","preventionTips":["Include unique surrounding lines (imports, function signatures, distinctive comments) in oldText.","Prefer hashline/line-anchored edits when a file has repeated boilerplate.","Count matches yourself before editing when constructing oldText programmatically."],"tags":["ambiguity","edit-tool","validation"],"backgroundTag":"ambiguous-match","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}