CherryHQ/cherry-studio · error · Error

Found multiple matches for old_string. Provide more surround

Error message

Found multiple matches for old_string. Provide more surrounding lines in old_string to identify the correct match.

What it means

Thrown by replaceWithFuzzyMatch when a replacer yielded a search substring that was found, but content.indexOf(search) !== content.lastIndexOf(search) for every candidate, and replaceAll is false. The matched text occurs more than once in the file, so a single replacement would be ambiguous. notFound is false (a match exists), so this branch rather than the not-found branch fires.

Source

Thrown at src/main/ai/mcp/servers/filesystem/types.ts:547

  for (const replacer of ALL_REPLACERS) {
    for (const search of replacer(content, oldString)) {
      const index = content.indexOf(search)
      if (index === -1) continue
      notFound = false
      if (replaceAll) {
        return content.replaceAll(search, newString)
      }
      const lastIndex = content.lastIndexOf(search)
      if (index !== lastIndex) continue
      return content.substring(0, index) + newString + content.substring(index + search.length)
    }
  }

  if (notFound) {
    throw new Error('old_string not found in content')
  }
  throw new Error(
    'Found multiple matches for old_string. Provide more surrounding lines in old_string to identify the correct match.'
  )
}

// ============================================================================
// Binary File Detection
// ============================================================================

// Check if a file is likely binary
export async function isBinaryFile(filePath: string): Promise<boolean> {
  try {
    const buffer = Buffer.alloc(4096)
    const fd = await fs.open(filePath, 'r')
    const { bytesRead } = await fd.read(buffer, 0, buffer.length, 0)
    await fd.close()

    if (bytesRead === 0) return false

View on GitHub (pinned to 726446b54c)

Solutions

  1. Add more surrounding lines (above and below) to old_string until it is unique in the file.
  2. If you intend to replace every occurrence, pass replaceAll=true.
  3. Include unique anchors (function name, comment, distinctive nearby line) in old_string.
  4. Count occurrences of old_string before editing to detect ambiguity early.

Example fix

// before: 'return null;' appears 3 times
replaceWithFuzzyMatch(content, 'return null;', 'return undefined;') // throws: Found multiple matches

// after: anchor with unique surrounding context
replaceWithFuzzyMatch(content, 'function getUser() {\n  return null;\n}', 'function getUser() {\n  return undefined;\n}')
Defensive patterns

Strategy: validation

Validate before calling

function isUnique(content: string, oldString: string): boolean {
  const first = content.indexOf(oldString)
  return first !== -1 && first === content.lastIndexOf(oldString)
}

Try / catch

try {
  replaceWithFuzzyMatch(content, oldString, newString)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Found multiple matches')) {
    // expand old_string with surrounding lines until unique, or set replaceAll=true
  } else throw e
}

Prevention

When it happens

Trigger: Editing a common snippet (e.g. a return statement, an import, a log line) that appears multiple times in the file without replaceAll=true and without enough surrounding context to disambiguate. The fuzzy replacers reduce whitespace/indentation differences but still surface the same substring at multiple indices.

Common situations: Boilerplate lines (closing braces, blank lines, identical log calls) repeated across the file; editing a symbol referenced in many places; old_string trimmed to the minimal unique-looking line that is actually not unique.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/af31d1217894b035. Report an issue: GitHub.