stablyai/orca · error · RuntimeError

click modifiers require modifier keys only

Error message

click modifiers require modifier keys only

What it means

Raised by click_modifier_keys (runtime.py:856) when the modifiers string, after splitting on '+', yields any empty or unrecognized part. The alias table (runtime.py:849-853) accepts ctrl/control/cmdorctrl/commandorcontrol, shift, alt/option, meta/super/win/cmd/command. Any other token — including literal '+' with nothing after, or a bare letter like 'a' — fails.

Source

Thrown at native/computer-use-linux/runtime.py:856

    down, up = buttons[button]
    for _ in range(parsed_count):
        Atspi.generate_mouse_event(round(x), round(y), "abs")
        Atspi.generate_mouse_event(round(x), round(y), down)
        time.sleep(0.03)
        Atspi.generate_mouse_event(round(x), round(y), up)


def click_modifier_keys(raw):
    if raw is None:
        return []
    aliases = {
        "ctrl": "ctrl", "control": "ctrl", "cmdorctrl": "ctrl", "commandorcontrol": "ctrl",
        "shift": "shift", "alt": "alt", "option": "alt",
        "meta": "super", "super": "super", "win": "super", "cmd": "super", "command": "super",
    }
    parts = [part.strip().lower() for part in str(raw).split("+")]
    if not parts or any(not part or part not in aliases for part in parts):
        raise RuntimeError("click modifiers require modifier keys only")
    return list(dict.fromkeys(aliases[part] for part in parts))


def modified_click_at(x, y, button, count, modifier_keys):
    xdotool = shutil.which("xdotool")
    is_wayland = os.environ.get("XDG_SESSION_TYPE", "").lower() == "wayland"
    if not xdotool or is_wayland:
        raise RuntimeError("modified clicks require xdotool on an X11 session")
    button_number = {"left": "1", "middle": "2", "right": "3"}[button]
    command = [xdotool, "mousemove", "--sync", str(round(x)), str(round(y))]
    for modifier in modifier_keys:
        command.extend(["keydown", modifier])
    command.extend(["click", "--repeat", str(count), "--delay", "35", button_number])
    for modifier in reversed(modifier_keys):
        command.extend(["keyup", modifier])
    try:
        subprocess.run(command, check=True, timeout=5)
    finally:

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Include only modifier tokens in modifiers: ctrl, shift, alt, meta/super (or their aliases).
  2. If you need a non-modifier key with the click, send a separate press_key/hotkey action instead.
  3. Build the modifiers string by joining only validated tokens with '+'.

Example fix

// before
{"tool":"click","modifiers":"ctrl+a"}
// after
{"tool":"click","modifiers":"ctrl"}
Defensive patterns

Strategy: validation

Validate before calling

MOD_ALIASES = {"ctrl","control","cmdorctrl","commandorcontrol","shift","alt","option","meta","super","win","cmd","command"}

def sanitize_modifiers(raw):
    if not raw:
        return None
    parts = [p.strip().lower() for p in str(raw).split("+")]
    if all(p in MOD_ALIASES for p in parts):
        return raw
    return None  # drop invalid -> plain click

Type guard

MOD_ALIASES = {"ctrl","control","cmdorctrl","commandorcontrol","shift","alt","option","meta","super","win","cmd","command"}

def is_valid_modifier_spec(raw) -> bool:
    if not raw:
        return True
    parts = [p.strip().lower() for p in str(raw).split("+")]
    return bool(parts) and all(p in MOD_ALIASES for p in parts)

Try / catch

try:
    run_operation(op)
except RuntimeError as e:
    if "modifiers require modifier keys only" in str(e):
        op.pop("modifiers", None)  # retry as plain click
    else:
        raise

Prevention

When it happens

Trigger: operation['modifiers'] for the 'click' tool is set to something like 'a', 'ctrl+', 'space', or 'ctrl+shift+a'. Multi-key chords are allowed only if every segment is a recognized modifier alias.

Common situations: An agent treats modifiers as a free-form key list and includes a non-modifier key; a caller joins keys with '+' but accidentally includes an empty segment; confusion between this (modifiers only) and hotkey (which allows full key specs).

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/7720eacd74c9f1f0. Report an issue: GitHub.