CoplayDev/unity-mcp · error · RuntimeError

{path}: expected 1 replacement for pattern, got {n}

Error message

{path}: expected 1 replacement for pattern, got {n}

What it means

Raised by replace_once in tools/prepare_unity_asset_store_release.py when a regex substitution did not match exactly once. The function is deliberately strict (it edits release files like package version/asmdef references) so that a drifted pattern surfaces immediately rather than silently leaving a file unchanged or over-replacing.

Source

Thrown at tools/prepare_unity_asset_store_release.py:39

).parents[1]  # adjust if you place elsewhere


def read_text(path: Path) -> str:
    return path.read_text(encoding="utf-8")


def write_text(path: Path, text: str) -> None:
    path.write_text(text, encoding="utf-8")


def replace_once(path: Path, pattern: str, repl: str) -> None:
    """
    Regex replace exactly once, else raise.
    """
    original = read_text(path)
    new, n = re.subn(pattern, repl, original, flags=re.MULTILINE)
    if n != 1:
        raise RuntimeError(
            f"{path}: expected 1 replacement for pattern, got {n}")
    if new != original:
        write_text(path, new)


def remove_line_exact(path: Path, line: str) -> None:
    original = read_text(path)
    lines = original.splitlines(keepends=True)

    removed = 0
    kept: list[str] = []
    for l in lines:
        if l.strip() == line:
            removed += 1
            continue
        kept.append(l)

    if removed != 1:

View on GitHub (pinned to c21bf496bc)

Solutions

  1. Open the path named in the message and re-derive the regex against current content so it matches exactly one line.
  2. If the token legitimately appears multiple times now, switch to a more specific pattern (anchored line) or update the script to replace all and re-verify.
  3. Re-run the script from a clean checkout to rule out partial prior edits leaving extra matches.

Example fix

# before
replace_once(pkg_json, r'"version"', '"1.0.0"')  # matches 0 or >1
# after
replace_once(pkg_json, r'^    "version": "[^"]+",', '    "version": "1.0.0",')  # anchored, exactly 1
Defensive patterns

Strategy: validation

Validate before calling

import re
n = len(re.findall(pattern, read_text(path), flags=re.MULTILINE))
if n != 1:
    raise SystemExit(f'{path}: pattern matches {n} times; re-derive the regex')

Type guard

def matches_exactly_once(text: str, pattern: str) -> bool:
    return len(re.findall(pattern, text, flags=re.MULTILINE)) == 1

Try / catch

try:
    replace_once(path, pattern, repl)
except RuntimeError as e:
    print(e); sys.exit(1)

Prevention

When it happens

Trigger: re.subn(pattern, repl, original, flags=re.MULTILINE) returns n != 1: 0 when the pattern no longer matches the file (content drifted), or >1 when the pattern is too broad and now matches multiple lines.

Common situations: The release-prep script was not updated after the target file's format changed; the version string or token appears more than once after a refactor; the regex was written against an older package version.

Related errors


AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13). Data as JSON: /api/errors/81ea2491a46ca19c. Report an issue: GitHub.