CoplayDev/unity-mcp · error · RuntimeError

{path}: expected to remove exactly 1 line '{line}', removed

Error message

{path}: expected to remove exactly 1 line '{line}', removed {removed}

What it means

Raised by remove_line_exact() when the target line content is not found exactly once in the file. The function strips each line and compares it to the literal passed in; it aborts if the count is 0 (line absent or reformatted) or >1 (duplicate lines). This is a build-time guard ensuring the Asset Store release script's source-edit assumptions still hold against the current source tree.

Source

Thrown at tools/prepare_unity_asset_store_release.py:58

            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:
        raise RuntimeError(
            f"{path}: expected to remove exactly 1 line '{line}', removed {removed}")

    write_text(path, "".join(kept))


def backup_dir(src: Path, backup_root: Path) -> Path:
    ts = dt.datetime.now().strftime("%Y%m%d-%H%M%S")
    backup_path = backup_root / f"{src.name}.backup.{ts}"
    shutil.copytree(src, backup_path)
    return backup_path


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Prepare MCPForUnity for Asset Store upload.")
    parser.add_argument(
        "--repo-root",
        default=str(REPO_ROOT_DEFAULT),

View on GitHub (pinned to c21bf496bc)

Solutions

  1. Open SetupWindowService.cs and grep for 'InitializeOnLoad' to see the current form of the attribute line.
  2. If the attribute sits on the same line as other tokens, update the literal passed to remove_line_exact (or switch to a regex-based removal) so the stripped comparison matches.
  3. If the attribute was already removed (removed=0), the edit is a no-op — skip the call or make it idempotent by treating removed==0 as success.
  4. If removed>1, disambiguate which occurrence to remove by adding surrounding context to the match logic.

Example fix

// before
remove_line_exact(setup_service, "[InitializeOnLoad]")

// after — idempotent: tolerate already-removed attribute
def remove_line_optional(path: Path, line: str) -> None:
    original = read_text(path)
    lines = original.splitlines(keepends=True)
    kept = [l for l in lines if l.strip() != line]
    if len(kept) != len(lines):
        write_text(path, "".join(kept))
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def can_remove_line(path: Path, line: str) -> bool:
    if not path.is_file():
        return False
    matches = [l for l in path.read_text(encoding="utf-8").splitlines() if l.strip() == line]
    return len(matches) == 1

# Before calling remove_line_exact:
if not can_remove_line(setup_service, "[InitializeOnLoad]"):
    print(f"Skip: line not found exactly once in {setup_service}")

Try / catch

try:
    remove_line_exact(setup_service, "[InitializeOnLoad]")
except RuntimeError as e:
    print(f"Warning: skipping attribute removal — {e}")
    # decide whether to abort or continue; the edit may already be applied

Prevention

When it happens

Trigger: Called as remove_line_exact(setup_service, "[InitializeOnLoad]"). Fires when SetupWindowService.cs no longer contains a standalone line whose stripped value equals exactly "[InitializeOnLoad]". Occurs if the attribute was already removed in a prior run, moved onto the same line as a class/method declaration (so strip() yields a longer string), wrapped in a region, or if the attribute now appears on multiple lines.

Common situations: The source file evolved after the release script was written — e.g. the [InitializeOnLoad] attribute was inlined, commented out, or merged with a comment. Also fires on a second accidental run if the first already removed the line (removed=0).

Related errors


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