{"record":{"id":"5096aa518c05a462","repo":"SeleniumHQ/selenium","slug":"expected-object-of-type-scrollorigin-got-type-s","errorCode":null,"errorMessage":"Expected object of type ScrollOrigin, got: {type(scroll_origin)}","messagePattern":"Expected object of type ScrollOrigin, got: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py/selenium/webdriver/common/action_chains.py","lineNumber":362,"sourceCode":"\n    def scroll_from_origin(self, scroll_origin: ScrollOrigin, delta_x: int, delta_y: int) -> ActionChains:\n        \"\"\"Scroll by a provided amount based on a scroll origin (element or viewport).\n\n        The scroll origin is either the center of an element or the upper left of the\n        viewport plus any offsets. If the origin is an element, and the element\n        is not in the viewport, the bottom of the element will first be\n        scrolled to the bottom of the viewport.\n\n        Args:\n            scroll_origin: Where scroll originates (viewport or element center) plus provided offsets.\n            delta_x: Distance along X axis to scroll using the wheel. A negative value scrolls left.\n            delta_y: Distance along Y axis to scroll using the wheel. A negative value scrolls up.\n\n        Raises:\n            MoveTargetOutOfBoundsException: If the origin with offset is outside the viewport.\n        \"\"\"\n        if not isinstance(scroll_origin, ScrollOrigin):\n            raise TypeError(f\"Expected object of type ScrollOrigin, got: {type(scroll_origin)}\")\n\n        self.w3c_actions.wheel_action.scroll(\n            origin=scroll_origin.origin,\n            x=scroll_origin.x_offset,\n            y=scroll_origin.y_offset,\n            delta_x=delta_x,\n            delta_y=delta_y,\n        )\n        return self\n\n    # Context manager so ActionChains can be used in a 'with .. as' statements.\n\n    def __enter__(self) -> ActionChains:\n        return self  # Return created instance of self.\n\n    def __exit__(self, _type, _value, _traceback) -> None:\n        pass  # Do nothing, does not require additional cleanup.\n","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/py/selenium/webdriver/common/action_chains.py#L344-L380","documentation":"`ActionChains.scroll_from_origin` requires a `ScrollOrigin` object (built via `ScrollOrigin.from_element(...)` or `ScrollOrigin.from_viewport(...)`). Passing anything else (a WebElement, a string, a tuple) raises `TypeError`. ScrollOrigin bundles the origin plus x/y offsets and is the only acceptable argument shape.","triggerScenarios":"`ActionChains(driver).scroll_from_origin(element, 0, 100)` (passing a WebElement directly), `scroll_from_origin(\"viewport\", 0, 100)` (a string), or `scroll_from_origin((0,0), 0, 100)` (a tuple). The developer forgot to wrap the origin in a ScrollOrigin.","commonSituations":"Mixing up `scroll_from_origin` with `scroll_to_element`/`scroll_by_amount`. Porting code from another library. Reading an outdated tutorial that passed a bare element.","solutions":["Wrap an element origin: `from selenium.webdriver.common.actions.wheel_input import ScrollOrigin; ActionChains(driver).scroll_from_origin(ScrollOrigin.from_element(el, 0, 0), 0, 100).perform()`.","Wrap a viewport origin: `ScrollOrigin.from_viewport(x_offset, y_offset)`.","If you just want to scroll to an element, use `scroll_to_element(element)` instead.","If you want pure delta scroll, use `scroll_by_amount(delta_x, delta_y)`."],"exampleFix":"// before\nActionChains(driver).scroll_from_origin(element, 0, 100).perform()  # TypeError\n// after\nfrom selenium.webdriver.common.actions.wheel_input import ScrollOrigin\nActionChains(driver).scroll_from_origin(ScrollOrigin.from_element(element), 0, 100).perform()","handlingStrategy":"type-guard","validationCode":"from selenium.webdriver.common.actions.wheel_input import ScrollOrigin\norigin = ScrollOrigin.from_element(element, 0, 0)\nassert isinstance(origin, ScrollOrigin), \"scroll_from_origin needs a ScrollOrigin\"\nActionChains(driver).scroll_from_origin(origin, 0, 100).perform()","typeGuard":"from selenium.webdriver.common.actions.wheel_input import ScrollOrigin\ndef is_scroll_origin(value) -> bool:\n    return isinstance(value, ScrollOrigin)","tryCatchPattern":"try:\n    ActionChains(driver).scroll_from_origin(origin, dx, dy).perform()\nexcept TypeError:\n    from selenium.webdriver.common.actions.wheel_input import ScrollOrigin\n    if hasattr(origin, \"id\"):\n        origin = ScrollOrigin.from_element(origin)\n    else:\n        origin = ScrollOrigin.from_viewport()\n    ActionChains(driver).scroll_from_origin(origin, dx, dy).perform()","preventionTips":["Always wrap origins with ScrollOrigin.from_element / from_viewport.","Use scroll_to_element or scroll_by_amount for simpler cases.","Type-hint the parameter as ScrollOrigin to catch mistakes statically."],"tags":["action-chains","scroll","type-check","wheel"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}