{"record":{"id":"04c247793c8723ed","repo":"oraios/serena","slug":"expression-matches-n-occurrences-please-revise","errorCode":null,"errorMessage":"Expression matches {n} occurrences. Please revise the expression to be more specific or enable allow_multiple_occurrences if this is expected.","messagePattern":"Expression matches (.+?) occurrences\\. Please revise the expression to be more specific or enable allow_multiple_occurrences if this is expected\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/serena/util/text_utils.py","lineNumber":476,"sourceCode":"        if self.mode == \"literal\":\n            regex = re.escape(needle)\n        elif self.mode == \"regex\":\n            regex = needle\n        else:\n            raise ValueError(f\"Invalid mode: '{self.mode}', expected 'literal' or 'regex'.\")\n\n        regex_flags = (re.MULTILINE | re.DOTALL) if self.regex_multiline else 0\n\n        # create replacement function with validation and backreference handling\n        repl_fn = self._create_replacement_function(regex, repl, regex_flags=regex_flags)\n\n        # perform replacement\n        updated_content, n = re.subn(regex, repl_fn, content, flags=regex_flags)\n\n        if n == 0:\n            raise ValueError(\"Error: No matches of search expression found.\")\n        if not self.allow_multiple_occurrences and n > 1:\n            raise ValueError(\n                f\"Expression matches {n} occurrences. \"\n                \"Please revise the expression to be more specific or enable allow_multiple_occurrences if this is expected.\"\n            )\n        return updated_content\n\n\n@dataclass\nclass ReplacementOccurrence:\n    \"\"\"A single prospective replacement of a pattern match within one file.\"\"\"\n\n    occurrence_id: str\n    \"\"\"stable, content-anchored identifier: '<relative_path>:<index_in_file>@<digest>'\"\"\"\n    relative_path: str\n    index_in_file: int\n    \"\"\"0-based index of this match among the matches within its file (in position order)\"\"\"\n    start: int\n    \"\"\"character offset of the match start within the file content\"\"\"\n    end: int","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/serena/util/text_utils.py#L458-L494","documentation":"replace() expects the expression to match exactly once unless allow_multiple_occurrences is set. When re.subn reports n > 1 matches, the library refuses to replace all of them blindly and asks you to make the expression more specific or opt in explicitly.","triggerScenarios":"Calling replace() with a pattern matching 2+ places in content while allow_multiple_occurrences=False (the default), e.g. a generic needle like 'version = ...' repeated in several sections.","commonSituations":"Editing boilerplate that appears in many files or blocks of the same file; overly broad regexes like '\\\\d+' or repeated comment markers; literal strings that occur in both header and body.","solutions":["Add surrounding unique context to the needle so it matches only the intended occurrence","Set allow_multiple_occurrences=True if replacing all occurrences is intended","Use an index/offset-based replacement or loop with per-occurrence context","Include a larger anchor span (function signature, section header) in the pattern"],"exampleFix":"// before\nreplacer.replace(content, 'timeout=30', 'timeout=60')  # appears 3 times\n// after\nreplacer.replace(content, r'(client_config:.*?timeout=)30', r'\\g<1>60')  # scoped, unique\n# or: TextReplacement(..., allow_multiple_occurrences=True)","handlingStrategy":"validation","validationCode":"n = len(re.findall(regex, content, flags=re.MULTILINE|re.DOTALL))\nif n > 1 and not allow_multiple:\n    raise ValueError(f'{n} matches; narrow the pattern or set allow_multiple_occurrences')","typeGuard":null,"tryCatchPattern":"try:\n    updated = editor.replace(content, needle, repl)\nexcept ValueError as e:\n    if 'matches' in str(e) and 'occurrences' in str(e):\n        editor.allow_multiple_occurrences = True\n        updated = editor.replace(content, needle, repl)\n    else:\n        raise","preventionTips":["Scope patterns with unique surrounding context","Count matches with re.findall before editing","Opt in to allow_multiple_occurrences only when replace-all is intended"],"tags":["regex","text-processing","multiple-matches"],"backgroundTag":"ambiguous-regex-match","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}