stablyai/orca · error · RuntimeError

direction is required

Error message

direction is required

What it means

Raised by scroll_at (runtime.py:884) when direction is None or strips to an empty string. Direction is a required field for the scroll tool because the wheel-event mapping (up/down/left/right) depends on it. This fires before the direction is lowercased and looked up.

Source

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

    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:
        subprocess.run(
            [xdotool, *[item for modifier in reversed(modifier_keys) for item in ("keyup", modifier)]],
            check=False,
            timeout=2,
        )


def scroll_at(x, y, direction, pages):
    if direction is None or str(direction).strip() == "":
        raise RuntimeError("direction is required")
    direction = str(direction).lower()
    wheel_events = {
        "up": ("b4p", "b4r"),
        "down": ("b5p", "b5r"),
        "left": ("b6p", "b6r"),
        "right": ("b7p", "b7r"),
    }
    if direction not in wheel_events:
        raise RuntimeError(f"unsupported scroll direction: {direction}")
    down, up = wheel_events[direction]
    page_count = max(1, math.ceil(require_positive_number(1 if pages is None else pages, "pages")))
    for _ in range(page_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)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Always set 'direction' to one of 'up', 'down', 'left', 'right' for scroll operations.
  2. If your controller has a default scroll direction, populate the field explicitly before dispatch.
  3. Reject empty direction in your own input layer rather than relying on the runtime.

Example fix

// before
{"tool":"scroll","pages":2}
// after
{"tool":"scroll","direction":"down","pages":2}
Defensive patterns

Strategy: validation

Validate before calling

DIRECTIONS = {"up", "down", "left", "right"}
direction = (raw_direction or "").strip().lower()
if direction not in DIRECTIONS:
    direction = "down"  # sane default
op = {"tool": "scroll", "direction": direction}

Type guard

def is_scroll_direction(value) -> bool:
    return (value or "").strip().lower() in {"up", "down", "left", "right"}

Try / catch

try:
    run_operation(op)
except RuntimeError as e:
    if "direction is required" in str(e):
        op["direction"] = "down"
    else:
        raise

Prevention

When it happens

Trigger: Calling the 'scroll' tool with operation['direction'] missing, null, or whitespace-only (' '). An empty string after .strip() is treated as absent.

Common situations: An agent omits direction assuming a default; a caller forwards a templated field that resolved to empty; whitespace from a malformed JSON value.

Related errors


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