can1357/oh-my-pi · error
Found ${occurrences} occurrences${pathSuffix}${moreMsg}:\n\n
Error message
Found ${occurrences} occurrences${pathSuffix}${moreMsg}:\n\n${previews}\n\nAdd more context lines to disambiguate. What it means
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.
Source
Thrown at packages/coding-agent/src/edit/diff.ts:917
replacements.sort((a, b) => a.startIndex - b.startIndex);
const parts: string[] = [];
let sourceIndex = 0;
for (const replacement of replacements) {
parts.push(normalizedContent.substring(sourceIndex, replacement.startIndex), replacement.text);
sourceIndex = replacement.endIndex;
}
parts.push(normalizedContent.substring(sourceIndex));
return { content: parts.join(""), count: replacements.length };
}
// Single replacement mode
const matchOutcome = findMatch(normalizedContent, normalizedOldText, {
allowFuzzy: options.fuzzy,
threshold,
});
if (matchOutcome.occurrences && matchOutcome.occurrences > 1) {
throw new Error(formatOccurrenceMatchError(matchOutcome.occurrences, matchOutcome.occurrencePreviews));
}
if (!matchOutcome.match) {
return { content: normalizedContent, count: 0 };
}
const match = matchOutcome.match;
const adjustedNewText = adjustIndentation(normalizedOldText, match.actualText, normalizedNewText);
normalizedContent =
normalizedContent.substring(0, match.startIndex) +
adjustedNewText +
normalizedContent.substring(match.startIndex + match.actualText.length);
return { content: normalizedContent, count: 1 };
}
// ═══════════════════════════════════════════════════════════════════════════
// Preview/Diff ComputationView on GitHub (pinned to 9690622007)
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.
Example fix
// before
replaceText(content, 'return null;', 'return undefined;', { fuzzy: false });
// after
replaceText(
content,
'function findUser(id: string) {\n return null;\n}',
'function findUser(id: string) {\n return undefined;\n}',
{ fuzzy: false }
); Defensive patterns
Strategy: validation
Validate before calling
const occurrences = content.split(oldText).length - 1;
if (occurrences !== 1) {
throw new Error(`oldText matches ${occurrences} times; add context to disambiguate`);
}
const result = replaceText(content, oldText, newText, options); Try / catch
try {
return replaceText(content, oldText, newText, { fuzzy: false });
} catch (e) {
if (e instanceof Error && e.message.includes('occurrences')) {
// retry with expanded context derived from occurrence previews in e.message
return replaceTextWithMoreContext(content, oldText, newText);
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- oldText must not be empty.
- Missing hashline snapshot tag for ${sectionPath}; use `${HL_
- Multiple hashline sections resolve to the same file (${previ
- agent:// URL cannot combine path extraction with ?q=
- Unsupported language '{value}'. Supported: {}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/4d47e15ebb1fe297.
Report an issue: GitHub.