{"record":{"id":"2618b46ac7e6a8ce","repo":"stablyai/orca","slug":"stale-element-frame-run-get-app-state-again-and-u","errorCode":null,"errorMessage":"stale element frame; run get-app-state again and use a fresh element index","messagePattern":"stale element frame; run get-app-state again and use a fresh element index","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"native/computer-use-linux/runtime.py","lineNumber":796,"sourceCode":"    for index in range(int(attempt(node.get_n_actions, 0) or 0)):\n        label = str(attempt(lambda i=index: node.get_action_name(i), \"\") or \"\").lower()\n        if label in priority:\n            return index\n        if fallback is None and any(term in label for term in (\"click\", \"press\", \"activate\")):\n            fallback = index\n    return fallback\n\n\ndef perform_action(node, index):\n    return bool(index is not None and attempt(lambda: node.do_action(int(index)), False))\n\n\ndef screen_point(window_rect, saved_element=None, x=None, y=None, node=None):\n    rect = screen_rect(node) if node is not None else None\n    if rect is not None:\n        return rect.x + rect.width / 2, rect.y + rect.height / 2\n    if saved_element is not None:\n        raise RuntimeError(\"stale element frame; run get-app-state again and use a fresh element index\")\n    if window_rect is None or x is None or y is None:\n        raise RuntimeError(\"coordinate action requires a visible window and coordinates\")\n    return window_rect.x + float(x), window_rect.y + float(y)\n\n\ndef require_positive_integer(value, name):\n    try:\n        parsed = int(value)\n    except (TypeError, ValueError):\n        raise RuntimeError(f\"{name} must be a positive integer\")\n    if parsed <= 0:\n        raise RuntimeError(f\"{name} must be a positive integer\")\n    return parsed\n\n\ndef require_positive_number(value, name):\n    try:\n        parsed = float(value)","sourceCodeStart":778,"sourceCodeEnd":814,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/native/computer-use-linux/runtime.py#L778-L814","documentation":"Raised by screen_point (runtime.py:791-796) when saved_element is not None (the caller passed an element index from a prior snapshot) but the live AT-SPI node's screen_rect returned None — meaning the element no longer has a visible extent (was scrolled off-screen, removed, hidden, or its window closed). Because the caller provided an element reference rather than explicit x/y, there is no coordinate fallback, so the bridge tells the caller the cached element is stale and to refresh.","triggerScenarios":"click/scroll/drag operation referenced operation.get('element') (a saved element handle) whose underlying AT-SPI node now returns no extent: UI reflowed (list scrolled, dialog dismissed, view switched), element recycled/removed, or window resized so the element is off-screen. screen_rect returns None when get_component_iface is null or width/height ≤ 0.","commonSituations":"Agent cached an element index from a get-app-state snapshot, performed intermediate actions that reflowed the UI, then tried to act on the stale element. Web apps with dynamic lists, virtualized scrollers, and route changes are common culprits; native apps with collapsing sidebars/animations also trigger it.","solutions":["Call get-app-state again to obtain a fresh snapshot and use a new element index.","Target by explicit x/y coordinates (operation.x/y) instead of an element handle when the UI is volatile.","After UI-changing actions (clicks that navigate, scrolls), refresh the snapshot before referencing element indices.","Reduce the time between snapshot and action to minimize reflow windows."],"exampleFix":"// before — reusing a stale element index after UI changed\n{ \"app\": \"Browser\", \"element\": 42, \"tool\": \"click\" }  // element 42 no longer has a rect\n\n// after — refresh snapshot, then target fresh index or coordinates\n// 1. call get-app-state\n// 2. find the element's new index (or its current x/y)\n{ \"app\": \"Browser\", \"x\": 320, \"y\": 480, \"tool\": \"click\" }","handlingStrategy":"retry","validationCode":"# Before acting on an element, verify it still has a rect\nnode = find_element(app, saved_element)\nif node is not None and screen_rect(node) is None:\n    # element is stale — refresh snapshot before action\n    snapshot = make_snapshot(query, include_screenshot=False)\n    # re-resolve the element index from the fresh snapshot","typeGuard":"def element_has_live_rect(app, saved_element) -> bool:\n    node = find_element(app, saved_element)\n    return node is not None and screen_rect(node) is not None","tryCatchPattern":"try:\n    point = screen_point(bounds, saved_element, x, y, node)\nexcept RuntimeError as exc:\n    if 'stale element frame' in str(exc):\n        snapshot = make_snapshot(query, include_screenshot=False)\n        # re-acquire element index or fall back to explicit x/y from the fresh snapshot\n        point = screen_point(bounds, None, fresh_x, fresh_y, None)\n    else:\n        raise","preventionTips":["Call get-app-state before referencing element indices after any UI-changing action.","Prefer explicit x/y coordinates when the UI is volatile.","Minimize the interval between snapshot and action to reduce reflow windows."],"tags":["linux","at-spi","staleness","element","coordinate","ui-reflow"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}