oraios/serena · error · ValueError

{len(problems)} of the given occurrence_ids could not be res

Error message

{len(problems)} of the given occurrence_ids could not be resolved - NO changes were applied:
{problem_lines}
Re-run with dry_run=True to obtain current occurrence ids.

What it means

replace_content (apply) supports selecting specific matches by occurrence_id obtained from a dry run. If any provided ids cannot be resolved against the freshly scanned occurrences, apply() raises this ValueError and deliberately applies NO changes (all-or-nothing semantics).

Source

Thrown at src/serena/tools/file_tools.py:286

            occurrences you expect to be replaced. If the actual count differs, nothing is changed and
            the list of prospective changes is returned. -1 disables the guard.
        :param max_answer_chars: if the output exceeds this many characters, a shortened version is
            returned. -1 uses the configured default.
        :return: in a dry run, the prospective changes; otherwise a summary of the applied replacements
        """
        replacer = MultiFileContentReplacer(mode=mode)
        files = self._collect_files(relative_path, paths_include_glob, paths_exclude_glob)
        occurrences = replacer.find_occurrences(files, needle, repl)
        contents = dict(files)

        if dry_run:
            return self._render_listing(replacer, occurrences, contents, max_answer_chars, dry_run=True)

        if occurrence_ids is not None:
            selected, problems = self._resolve_occurrence_ids(occurrence_ids, occurrences)
            if problems:
                problem_lines = "\n".join(f"  {p}" for p in problems)
                raise ValueError(
                    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)

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Re-run the operation with dry_run=True to get fresh occurrence ids, then apply with the new ids
  2. Confirm the same needle, repl, mode, path, and globs are used for the dry run and the apply call
  3. If the intent is to replace all matches, omit occurrence_ids entirely
  4. Check the listed problem lines to identify which ids are stale or invalid

Example fix

// before
result = agent.replace_content(needle="foo", repl="bar", occurrence_ids=["o1","o9"])
// after
dry = agent.replace_content(needle="foo", repl="bar", dry_run=True)
ids = [o.id for o in dry.occurrences]
result = agent.replace_content(needle="foo", repl="bar", occurrence_ids=ids)
Defensive patterns

Strategy: retry

Validate before calling

dry = agent.replace_content(needle=needle, repl=repl, dry_run=True)
valid_ids = {o.id for o in dry.occurrences}
assert set(occurrence_ids) <= valid_ids, "stale occurrence ids"

Type guard

def ids_fresh(ids, dry_run_result) -> bool:
    return all(i in {o.id for o in dry_run_result.occurrences} for i in ids)

Try / catch

try:
    agent.replace_content(needle, repl, occurrence_ids=ids)
except ValueError as e:
    if "could not be resolved" in str(e):
        dry = agent.replace_content(needle, repl, dry_run=True)
        agent.replace_content(needle, repl, occurrence_ids=[o.id for o in dry.occurrences])
    else:
        raise

Prevention

When it happens

Trigger: Calling replace_content with occurrence_ids from an earlier dry run after the file (or other matching files) changed; passing ids from a different needle/pattern than the current call; malformed ids outside the valid range.

Common situations: Two-step edit workflows where an edit happened between the dry run and the apply; concurrent modification by an editor or another agent; reusing ids across multiple replace operations.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/3d9c6bcc9b478bb6. Report an issue: GitHub.