{"record":{"id":"2138d77b9b56a2e7","repo":"CherryHQ/cherry-studio","slug":"old-string-not-found-in-content","errorCode":null,"errorMessage":"old_string not found in content","messagePattern":"old_string not found in content","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/servers/filesystem/types.ts","lineNumber":545,"sourceCode":"\n  let notFound = true\n\n  for (const replacer of ALL_REPLACERS) {\n    for (const search of replacer(content, oldString)) {\n      const index = content.indexOf(search)\n      if (index === -1) continue\n      notFound = false\n      if (replaceAll) {\n        return content.replaceAll(search, newString)\n      }\n      const lastIndex = content.lastIndexOf(search)\n      if (index !== lastIndex) continue\n      return content.substring(0, index) + newString + content.substring(index + search.length)\n    }\n  }\n\n  if (notFound) {\n    throw new Error('old_string not found in content')\n  }\n  throw new Error(\n    'Found multiple matches for old_string. Provide more surrounding lines in old_string to identify the correct match.'\n  )\n}\n\n// ============================================================================\n// Binary File Detection\n// ============================================================================\n\n// Check if a file is likely binary\nexport async function isBinaryFile(filePath: string): Promise<boolean> {\n  try {\n    const buffer = Buffer.alloc(4096)\n    const fd = await fs.open(filePath, 'r')\n    const { bytesRead } = await fd.read(buffer, 0, buffer.length, 0)\n    await fd.close()\n","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/filesystem/types.ts#L527-L563","documentation":"Thrown by replaceWithFuzzyMatch when none of the nine replacers (Simple, LineTrimmed, BlockAnchor, WhitespaceNormalized, IndentationFlexible, EscapeNormalized, TrimmedBoundary, ContextAware, MultiOccurrence) yields any substring that content.indexOf can locate. The variable notFound stays true through the whole ALL_REPLACERS loop, meaning the old_string is absent from the content beyond what fuzzy matching can recover.","triggerScenarios":"Editing a file with old_string that no longer matches after the file changed on disk; old_string copied from a different file; content was reloaded from a stale cache; old_string includes lines that were already edited in a prior step of the same session.","commonSituations":"Multi-step edit where step 1 changed the region step 2 targets; LLM hallucinated old_string from memory rather than a fresh read; trailing whitespace/line-ending (CRLF vs LF) differences beyond what the normalization replacers cover (e.g. BOM, mixed encodings); file replaced wholesale between read and edit.","solutions":["Re-read the file to get current content, then copy old_string verbatim from that read.","Normalize line endings (CRLF -> LF) on both content and old_string before editing.","Shorten old_string to a unique anchor that is more likely to survive the fuzzy replacers, or expand it with exact surrounding context.","Confirm you are editing the same file path that was read (no path mismatch)."],"exampleFix":"// before\nreplaceWithFuzzyMatch(staleContent, 'const x = 1;', 'const x = 2;') // throws: old_string not found\n\n// after\nconst fresh = await fs.readFile(target, 'utf-8')\nreplaceWithFuzzyMatch(fresh, 'const x = 1;', 'const x = 2;')","handlingStrategy":"validation","validationCode":"function canFind(content: string, oldString: string): boolean {\n  // cheapest signal before invoking fuzzy matching\n  return content.includes(oldString) ||\n    content.split('\\n').some(l => l.trim() === oldString.trim())\n}","typeGuard":null,"tryCatchPattern":"try {\n  replaceWithFuzzyMatch(content, oldString, newString)\n} catch (e) {\n  if (e instanceof Error && e.message === 'old_string not found in content') {\n    // re-read the file and rebuild old_string from the fresh content\n  } else throw e\n}","preventionTips":["Always re-read the file immediately before editing; never edit against a cached snapshot.","Normalize line endings (CRLF -> LF) on both sides before editing.","Copy old_string verbatim from the most recent read output, including exact whitespace.","Prefer minimal unique anchors expanded with surrounding context over large guess blocks."],"tags":["filesystem","validation","mcp","edit-tool","fuzzy-match"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}