{"record":{"id":"cc970a2b26fa38ad","repo":"stablyai/orca","slug":"window-not-focused-keyboard-input-requires-the-ta-cc970a","errorCode":null,"errorMessage":"window_not_focused: keyboard input requires the target window to be focused; retry with --restore-window","messagePattern":"window_not_focused: keyboard input requires the target window to be focused; retry with --restore-window","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"native/computer-use-linux/runtime.py","lineNumber":192,"sourceCode":"        check=False,\n        stdout=subprocess.DEVNULL,\n        stderr=subprocess.DEVNULL,\n    )\n\n\ndef require_keyboard_focus(window, operation):\n    if has_state(window, Atspi.StateType.ACTIVE):\n        return\n    if operation.get(\"restoreWindow\"):\n        deadline = time.monotonic() + 0.5\n        while time.monotonic() < deadline:\n            if has_state(window, Atspi.StateType.ACTIVE):\n                return\n            time.sleep(0.05)\n        if has_state(window, Atspi.StateType.ACTIVE):\n            return\n        raise RuntimeError(\"window_not_focused: keyboard input requires the target window to be focused; restoreWindow was requested but the target window is still not focused; bring it forward manually or check desktop permissions\")\n    raise RuntimeError(\"window_not_focused: keyboard input requires the target window to be focused; retry with --restore-window\")\n\n\ndef app_matches(app, query):\n    needle = str(query or \"\").strip().lower()\n    if not needle:\n        return False\n    if needle.startswith(\"pid:\"):\n        requested_pid = parse_positive_pid(needle[4:])\n        return requested_pid is not None and pid_of(app) == requested_pid\n    if needle.isdigit() and int(needle) > 0 and pid_of(app) == int(needle):\n        return True\n    haystacks = [name_of(app).lower()] + [name_of(window).lower() for _, window in windows_for(app)]\n    return any(value == needle or needle in value for value in haystacks)\n\n\ndef parse_positive_pid(value):\n    return int(value) if value.isdigit() and int(value) > 0 else None\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/native/computer-use-linux/runtime.py#L174-L210","documentation":"Raised by require_keyboard_focus (runtime.py:192) when the target window is not ACTIVE and the caller did NOT set operation.get('restoreWindow'). This is the 'hint to retry correctly' variant: the bridge detected keyboard input would go to the wrong window and tells the caller exactly how to fix the next attempt — pass restoreWindow so the bridge attempts to activate the window first (the path in error 493). Contrast with 493 which fires when restoreWindow WAS set but failed.","triggerScenarios":"type_text/press_key/hotkey/paste_text operation dispatched while another window has focus, and the operation JSON omitted 'restoreWindow' (or set it false). The AT-SPI ACTIVE state belongs to a different window, so synthetic keys (Atspi.generate_keyboard_event) would land in the wrong app.","commonSituations":"Agent performed a click in app A (which may or may not have activated it depending on the click path), then immediately called type_text without restoreWindow, and the previously-focused app B still holds ACTIVE. Common after accessibility-path clicks that don't change focus.","solutions":["Retry the same operation with restoreWindow:true — the bridge will attempt grab_focus/xdotool before requiring focus.","Always pair keyboard operations with restoreWindow unless you've just verified focus via get-app-state's focusedSummary.","After a click on app A, optionally verify with a fresh snapshot that A holds ACTIVE before typing.","If restoreWindow still fails (error 493), restore focus manually."],"exampleFix":"// before — keyboard op without restore\n{ \"app\": \"Firefox\", \"tool\": \"type_text\", \"text\": \"hi\" }\n\n// after — let the bridge activate the window first\n{ \"app\": \"Firefox\", \"tool\": \"type_text\", \"text\": \"hi\", \"restoreWindow\": true }","handlingStrategy":"retry","validationCode":"# If window lacks focus, set restoreWindow before dispatch\nif not window_has_focus(window):\n    operation = {**operation, 'restoreWindow': True}","typeGuard":"def needs_restore_window(window, operation) -> bool:\n    return not has_state(window, Atspi.StateType.ACTIVE) and not operation.get('restoreWindow')","tryCatchPattern":"try:\n    run_operation(operation)\nexcept RuntimeError as exc:\n    if 'retry with --restore-window' in str(exc):\n        operation = {**operation, 'restoreWindow': True}\n        run_operation(operation)\n    else:\n        raise","preventionTips":["Always pair keyboard operations (type_text, press_key, hotkey, paste_text) with restoreWindow:true.","After clicks that don't change focus (accessibility-path clicks), verify focus via get-app-state before typing.","Wrap keyboard ops in a retry that adds restoreWindow on this specific message."],"tags":["linux","at-spi","focus","keyboard","window","retry-hint"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}