stablyai/orca · error · RuntimeError

unsupported scroll direction: {direction}

Error message

unsupported scroll direction: {direction}

What it means

Raised by scroll_at (runtime.py:893) when the lowercased direction is not a key in wheel_events — i.e. not one of 'up', 'down', 'left', 'right'. These map to AT-SPI mouse button codes b4/b5/b6/b7 (the four wheel axes). It fires only for non-empty, unrecognized directions; empty ones are caught earlier by error 507.

Source

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

        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)


def drag_between(start, end):
    Atspi.generate_mouse_event(round(start[0]), round(start[1]), "abs")
    Atspi.generate_mouse_event(round(start[0]), round(start[1]), "b1p")
    for step in range(1, 13):
        x = start[0] + (end[0] - start[0]) * step / 12
        y = start[1] + (end[1] - start[1]) * step / 12
        Atspi.generate_mouse_event(round(x), round(y), "abs")
        time.sleep(0.02)
    Atspi.generate_mouse_event(round(end[0]), round(end[1]), "b1r")

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Map your direction vocabulary to 'up'/'down'/'left'/'right' before sending the operation.
  2. Validate direction against an allowlist in your controller.
  3. Treat diagonal/other directions as two separate scroll calls on different axes.

Example fix

// before
{"tool":"scroll","direction":"towards-bottom"}
// after
{"tool":"scroll","direction":"down"}
Defensive patterns

Strategy: type-guard

Validate before calling

DIRECTIONS = {"up", "down", "left", "right"}
direction = str(raw_direction).strip().lower()
if direction not in DIRECTIONS:
    raise ValueError(f"direction must be one of {sorted(DIRECTIONS)}")
op = {"tool": "scroll", "direction": direction}

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: operation['direction'] for the scroll tool is a value like 'north', 'top', 'vertical', 'scroll-down', or 'UP' (case-insensitive match is handled, so case is not the issue).

Common situations: An agent uses a natural-language direction that isn't normalized; a caller exposes a different vocabulary ('north'/'south') and forgets to map it; a typo like 'dwon'.

Related errors


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