stablyai/orca · error · RuntimeError

{name} must be a positive number

Error message

{name} must be a positive number

What it means

Raised by require_positive_number at runtime.py:816 when float(value) raises TypeError or ValueError — i.e. the value is not parseable as a number at all (None where not defaulted, a non-numeric string, a dict/list). The sole call site passes name='pages' via scroll_at (runtime.py:895), which itself defaults None to 1, so this fires only for genuinely unparseable input.

Source

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

        raise RuntimeError("coordinate action requires a visible window and coordinates")
    return window_rect.x + float(x), window_rect.y + float(y)


def require_positive_integer(value, name):
    try:
        parsed = int(value)
    except (TypeError, ValueError):
        raise RuntimeError(f"{name} must be a positive integer")
    if parsed <= 0:
        raise RuntimeError(f"{name} must be a positive integer")
    return parsed


def require_positive_number(value, name):
    try:
        parsed = float(value)
    except (TypeError, ValueError):
        raise RuntimeError(f"{name} must be a positive number")
    if not math.isfinite(parsed) or parsed <= 0:
        raise RuntimeError(f"{name} must be a positive number")
    return parsed


def require_non_empty_string(value, name):
    if value is None or str(value) == "":
        raise RuntimeError(f"{name} is required")
    return str(value)


def click_at(x, y, button, count, modifiers=None):
    button = (button or "left").lower()
    buttons = {"left": ("b1p", "b1r"), "right": ("b3p", "b3r"), "middle": ("b2p", "b2r")}
    if button not in buttons:
        raise RuntimeError(f"unsupported mouse button: {button}")
    parsed_count = require_positive_integer(1 if count is None else count, "click_count")
    modifier_keys = click_modifier_keys(modifiers)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Send pages as a number literal (int or float) in the operation JSON.
  2. If pages is optional, omit the field rather than sending null/empty so the default of 1 applies.
  3. Validate and coerce pages to float on the caller side before dispatching the scroll operation.

Example fix

# before
{"tool":"scroll","direction":"down","pages":"few"}
# after
{"tool":"scroll","direction":"down","pages":3}
Defensive patterns

Strategy: validation

Validate before calling

def coerce_pages(raw):
    if raw is None:
        return 1
    f = float(raw)  # raises TypeError/ValueError -> caller handles
    return f

# guard before dispatch
try:
    pages = float(raw_pages)
except (TypeError, ValueError):
    pages = 1

Type guard

def is_parseable_number(value) -> bool:
    try:
        float(value)
        return True
    except (TypeError, ValueError):
        return False

Try / catch

try:
    run_operation(op)
except RuntimeError as e:
    if "must be a positive number" in str(e):
        op["pages"] = 1
    else:
        raise

Prevention

When it happens

Trigger: Calling the 'scroll' tool with operation['pages'] set to a non-numeric string ('few'), an empty string '', a list/dict, or another non-float-coercible type. NaN strings like 'NaN' parse to float without error and instead trip the isfinite check (error 502), not this one.

Common situations: A caller serializes pages from a loosely-typed JSON source and forwards 'lots' or an object; an LLM agent hallucinates a word instead of a number; a wrapper passes the wrong field type.

Related errors


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