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
- Include only modifier tokens in modifiers: ctrl, shift, alt, meta/super (or their aliases).
- If you need a non-modifier key with the click, send a separate press_key/hotkey action instead.
- 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
- Include only modifier tokens (ctrl/shift/alt/meta and aliases) in modifiers.
- For non-modifier keys, send a separate press_key/hotkey action.
- Validate each '+'-separated token against the alias table before dispatch.
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
- unsupported mouse button: {button}
- {name} must be a positive number
- {name} is required
- direction is required
- unsupported scroll direction: {direction}
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/7720eacd74c9f1f0.
Report an issue: GitHub.