CoplayDev/unity-mcp · error · RuntimeError
unknown edit op: {op}; allowed: {allowed}. Use 'op' (aliases
Error message
unknown edit op: {op}; allowed: {allowed}. Use 'op' (aliases accepted: type/mode/operation). What it means
In script_apply_edits, after checking op is non-empty, the dispatch chain (prepend, append, anchor_insert, replace_range, regex_replace) is evaluated. If op matches none of these, the else branch fires listing the five allowed values. This means the caller provided a recognized-but-unsupported operation name, or a typo. Unlike error 176 (op missing), here op IS present but has an unrecognized value.
Source
Thrown at Server/src/services/tools/script_apply_edits.py:455
if line <= len(lines):
return sum(len(l) for l in lines[: line - 1]) + (col - 1)
return sum(len(l) for l in lines)
a = index_of(start_line, start_col)
b = index_of(end_line, end_col)
text = text[:a] + replacement + text[b:]
elif op == "regex_replace":
pattern = edit.get("pattern", "")
repl = edit.get("replacement", "")
# Translate $n backrefs (our input) to Python \g<n>
repl_py = re.sub(r"\$(\d+)", r"\\g<\1>", repl)
count = int(edit.get("count", 0)) # 0 = replace all
flags = re.MULTILINE
if edit.get("ignore_case"):
flags |= re.IGNORECASE
text = re.sub(pattern, repl_py, text, count=count, flags=flags)
else:
allowed = "anchor_insert, prepend, append, replace_range, regex_replace"
raise RuntimeError(
f"unknown edit op: {op}; allowed: {allowed}. Use 'op' (aliases accepted: type/mode/operation).")
return text
def _find_best_anchor_match(pattern: str, text: str, flags: int, prefer_last: bool = True):
"""
Find the best anchor match using improved heuristics.
For patterns like \\s*}\\s*$ that are meant to find class-ending braces,
this function uses heuristics to choose the most semantically appropriate match:
1. If prefer_last=True, prefer the last match (common for class-end insertions)
2. Use indentation levels to distinguish class vs method braces
3. Consider context to avoid matches inside strings/comments
Args:
pattern: Regex pattern to search for
text: Text to search in View on GitHub (pinned to c21bf496bc)
Solutions
- Use one of the exact allowed values: anchor_insert, prepend, append, replace_range, regex_replace.
- Check for typos and abbreviations — the match is exact and case-insensitive.
- If you need to delete text, use replace_range with text="" covering the range, or regex_replace with an empty replacement.
Example fix
// before
edits=[{"op": "insert", "anchor": "class Foo {", "text": "// new\n"}]
// after
edits=[{"op": "anchor_insert", "anchor": "class Foo {", "position": "before", "text": "// new\n"}] Defensive patterns
Strategy: validation
Validate before calling
ALLOWED_OPS = {"anchor_insert", "prepend", "append", "replace_range", "regex_replace"}
for i, edit in enumerate(edits):
op = (edit.get("op") or edit.get("operation") or edit.get("type") or edit.get("mode") or "").strip().lower()
if op and op not in ALLOWED_OPS:
raise ValueError(f"Edit {i} has unknown op '{op}'. Allowed: {sorted(ALLOWED_OPS)}") Type guard
ALLOWED_OPS = {"anchor_insert", "prepend", "append", "replace_range", "regex_replace"}
def edit_has_recognized_op(edit: dict) -> bool:
op = (edit.get("op") or edit.get("operation") or edit.get("type") or edit.get("mode") or "").strip().lower()
return op == "" or op in ALLOWED_OPS Prevention
- Use exact op names: anchor_insert, prepend, append, replace_range, regex_replace.
- For deletion, use replace_range with text="" or regex_replace with empty replacement.
- Validate op names against the allowed set before applying edits.
When it happens
Trigger: A caller uses op='insert' (should be 'anchor_insert'); op='replace' (should be 'replace_range'); op='delete' (not supported); a typo like 'apend' or 'replce'; a caller assumes an op like 'overwrite' or 'line_insert' exists.
Common situations: An LLM invents a plausible op name not in the allowed set; a caller abbreviates an op name; documentation/version mismatch where an op was renamed; a caller confuses this tool's ops with another editor's vocabulary (e.g., LSP TextDocumentEdit operations).
Related errors
- op is required; allowed: {allowed}. Use 'op' (aliases accept
- 'commands' must be a non-empty list of command specification
- batch_execute supports up to {max_commands} commands (config
- Command at index {index} must be an object with 'tool' and '
- Command at index {index} is missing a valid 'tool' name
AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13).
Data as JSON: /api/errors/ea17c087f94758a6.
Report an issue: GitHub.