oraios/serena · error · ValueError
expected_count={expected_count}, but the pattern matches {le
Error message
expected_count={expected_count}, but the pattern matches {len(occurrences)} occurrence(s) - NO changes were applied. Review the prospective changes below; re-issue with the corrected expectation, a refined pattern, or occurrence_ids selecting the intended subset.
{listing} What it means
apply() supports an expected_count safety check: if specified (>= 0) and the number of pattern matches differs from it, no changes are applied and a ValueError including a dry-run-style listing of the prospective changes is raised. This protects against unintended bulk replacements when the file drifted or the pattern is broader than expected.
Source
Thrown at src/serena/tools/file_tools.py:305
f"{len(problems)} of the given occurrence_ids could not be resolved - NO changes were applied:\n"
f"{problem_lines}\n"
"Re-run with dry_run=True to obtain current occurrence ids."
)
if not selected:
raise ValueError("occurrence_ids is empty - pass at least one id from a dry run, or omit the parameter to replace all.")
return self._apply_occurrences(replacer, selected, contents, needle, repl)
# blind apply (no ids)
if not occurrences:
raise ValueError(
"No occurrences of the pattern were found - NO changes were applied. "
"Check the mode (a literal needle containing regex metacharacters must use mode 'literal'; "
"wildcards require mode 'regex') and the path/glob restrictions, "
"or locate the content with search_for_pattern first."
)
if expected_count >= 0 and len(occurrences) != expected_count:
listing = self._render_listing(replacer, occurrences, contents, max_answer_chars, dry_run=False)
raise ValueError(
f"expected_count={expected_count}, but the pattern matches {len(occurrences)} occurrence(s) - "
f"NO changes were applied. Review the prospective changes below; re-issue with the corrected "
f"expectation, a refined pattern, or occurrence_ids selecting the intended subset.\n{listing}"
)
ambiguous = [o for o in occurrences if o.is_ambiguous]
if ambiguous:
listing = self._render_listing(replacer, occurrences, contents, max_answer_chars, dry_run=False)
raise ValueError(
f"{len(ambiguous)} occurrence(s) are ambiguous (the pattern matches again inside the matched text, "
f"indicating possible over-matching) - NO changes were applied. Review the prospective changes below "
f"and either refine the pattern or explicitly select occurrences via occurrence_ids.\n{listing}"
)
return self._apply_occurrences(replacer, occurrences, contents, needle, repl)
def _collect_files(self, relative_path: str, paths_include_glob: str, paths_exclude_glob: str) -> list[tuple[str, str]]:
"""Collects (relative_path, content) pairs of the non-ignored files in scope, in sorted path order."""
relative_path = relative_path.strip()
if relative_path:View on GitHub (pinned to 7fcbca7e62)
Solutions
- Inspect the listing in the error to see every match, then re-issue with the correct expected_count
- Refine the pattern (or add path/glob restrictions) so it matches exactly the intended occurrences
- Use occurrence_ids from a dry run to select exactly the intended subset
- Set expected_count=-1 (omit) if the count is genuinely variable and the replacement is safe for all matches
Example fix
// before
agent.replace_content(needle="oldName", repl="newName", expected_count=1)
// after
listing = agent.replace_content(needle="oldName", repl="newName", dry_run=True)
# review matches, then select subset:
agent.replace_content(needle="oldName", repl="newName",
occurrence_ids=[listing.occurrences[0].id]) Defensive patterns
Strategy: try-catch
Validate before calling
dry = agent.replace_content(needle, repl, dry_run=True)
assert len(dry.occurrences) == expected_count, \
f"{len(dry.occurrences)} matches, expected {expected_count}" Type guard
def count_matches(needle, path) -> int:
return len(agent.search_for_pattern(needle, path=path)) Try / catch
try:
agent.replace_content(needle, repl, expected_count=n)
except ValueError as e:
if "expected_count" in str(e):
# listing of matches is embedded in the message; refine pattern or ids
dry = agent.replace_content(needle, repl, dry_run=True)
agent.replace_content(needle, repl, occurrence_ids=[o.id for o in dry.occurrences[:n]])
else:
raise Prevention
- Dry-run first and verify the match count matches expectations
- Constrain patterns with paths/globs to narrow scope
- Use occurrence_ids for surgical subset replacements
When it happens
Trigger: Calling replace_content with expected_count=N where the pattern matches M != N occurrences; the target text appears more times than expected (e.g. in comments, tests, or generated code); a previous edit already changed the count.
Common situations: Refactoring scripts written against an earlier file version; needles that also match inside strings/comments/docstrings; case-insensitive or wildcard patterns matching more than the single intended site.
Related errors
- {len(problems)} of the given occurrence_ids could not be res
- occurrence_ids is empty - pass at least one id from a dry ru
- No occurrences of the pattern were found - NO changes were a
- {len(ambiguous)} occurrence(s) are ambiguous (the pattern ma
- The content of {path} changed while replacing (occurrence {e
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/fcbdd3202fd18a2d.
Report an issue: GitHub.