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
- Open the path named in the message and re-derive the regex against current content so it matches exactly one line.
- 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.
- 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
- Re-derive release-prep regexes whenever target file formats change
- Anchor patterns to a full line for uniqueness
- Run release prep from a clean checkout to avoid double matches
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
- Manifest template not found: {MANIFEST_TEMPLATE}
- Icon not found: {icon_path}
- MCPB file was not created: {output_path}
- No Unity editor binary found. Searched:\n
- Color array must have 3 or 4 elements.
AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13).
Data as JSON: /api/errors/81ea2491a46ca19c.
Report an issue: GitHub.