返回 CodeWhale
refusal-codes.md
1 # Refusal codes and the move that fixes them
2
3 Every refusal is structured: `ok:false` with an `error.code` you can branch on.
4 Never retry a refusal unchanged — re-observe, re-target, or change route.
5
6 ## Target and state
7
8 | code | meaning | move |
9 | --- | --- | --- |
10 | `element_stale` | the live tree no longer matches the observation (user or app changed it) | `get_app_state` again and re-target |
11 | `unknown_state` | no observation on this computer (or the app was rebound) | observe first; bare indices bind the latest observation of the bound app |
12 | `state_wrong_computer` | `state_id` came from a different computer | observe on the computer you are acting on |
13 | `unknown_element` | index outside the cached tree | observe again; use `query`/`role` filters |
14 | `element_no_geometry` | element has no frame | use a coordinate target from a fresh raster |
15 | `degenerate_frame` | zero-size placeholder row (virtualized list) | scroll the real row into view, re-observe |
16 | `target_outside_raster` | coordinate outside the bound screenshot | take a fresh screenshot/zoom and use its pixels |
17 | `no_raster` | coordinate target with no raster bound | `screenshot` first |
18 | `window_blocked_by_modal_sheet` | an accessibility press would cross a sheet | deal with the sheet first |
19 | `window_ambiguous` | two windows share the resolved window's frame (stacked or identical geometry) | `list_windows`, pick one, pass `window_id` (or re-target the press) |
20 | `window_target_not_found` | PID has no eligible window | `list_windows`; open or pick the right app |
21
22 ## Route and policy
23
24 | code | meaning | move |
25 | --- | --- | --- |
26 | `background_focus_required` | background mode refuses raw pointer gestures (the window route borrows key focus) | use element targets; foreground control needs the user's explicit authorization |
27 | `bg_dispatch_unavailable` | the window-routed pointer cannot be resolved on this helper | update Computer Use or use element targets — the user's cursor is never used instead |
28 | `real_pointer_refused` | a request tried to drive the user's cursor | there is no such route; use the window-routed pointer tools |
29 | `background_scroll_unavailable` | no scrollbar at that point | target an observed scroll area |
30 | `menu_item_not_found` | exact title not present (menus expose items only while open) | check the exact title; an ellipsis is part of it |
31 | `menu_item_disabled` | item present but the app refuses it right now (often a missing key window) | use the window's own control element instead |
32 | `app_not_found` | selector missed — `open_application` names/bundle ids that resolve nowhere and dead pids report it too | `list_apps` (or `all:true`) for exact names/pids |
33 | `ambiguous_application` | an app name or bundle id matched several running apps (observation, input or `kill_app`) | pass `pid` to choose one |
34 | `protected_application` | the target is the Computer Use helper or its host | name the intended app instead; these cannot be terminated through the plugin |
35 | `browser_not_running` | browser action before `browser {action:"start"}` (or the browser went away) | start it; a closed CDP connection clears the session state |
36 | `browser_not_installed` | no Chromium-family browser found | install one, or set `CODEWHALE_CU_BROWSER_APP` to the app path |
37 | `selector_not_found` | no element matches the CSS selector on the current page | re-check the selector against a fresh `browser {action:"screenshot"}` or `browser {action:"status"}` |
38 | `unsupported_runtime` | this Node has no global WebSocket (browser transport) | use Node 22+ for the daemon/server running the plugin |
39 | `not_granted` | the session's capability grant (`CODEWHALE_CU_GRANT`) does not include this tool | work inside the grant; the host narrowed it deliberately |
40 | `consent_required` | no user decision exists for this app on the local computer | ask the user, then record it: `consent {action:"allow"\|"deny", app:"…"}` |
41 | `app_denied` | the user denied this app — the deny covers every spelling of it | do not work around it; only they can `consent {action:"revoke"}` |
42 | `consent_needs_user` | a consent allow/revoke, a `confirm`, `app_script`, or computer register/spawn was called without the user's own decision | ask the user; the host shows them the exact call — never retry it as a model call or a `run_actions` step |
43 | `consent_declined` | the user declined the host's prompt for that call | do not retry; continue without it or ask them |
44 | `foreground_consent_required` | `activate:true` needs the separate foreground decision | ask, then `consent {action:"allow"\|"deny", scope:"foreground"}` — or keep working background (`activate:false`) |
45 | `confirmation_required` | the click or press would activate a pay/buy/order/send/transfer/delete control | stop and show the user exactly what will happen; only on their approval, `consent {action:"allow", confirm:"<token>"}` and repeat the identical call |
46 | `confirmation_unknown` | the confirmation token is unknown, used, or expired | repeat the original call for a fresh token and ask the user again |
47 | `script_refused` | `app_script` would reach a shell, Cocoa, dynamic code, a terminal app, or an app it does not name with a literal | use the host's shell for shell work, or name the app literally; never rewrite the script to get past the check |
48 | `not_replayable` | a trajectory step had its entered text redacted, so replay stops there | redo that step by hand |
49 | `foreground_denied` | the user denied shared-desktop (foreground) control | work background-only; do not retry `activate:true` |
50 | `frame_refused` | the app refused both the position and the size write | the window is fullscreen, tiled or otherwise not movable by the app |
51 | `trajectory_not_found` | no trajectory file matches the id (or none exist) | `trajectory {action:"status"}` lists recent files |
52 | `replay_too_large` | the trajectory exceeds the 200-turn replay cap | split it, or replay a pruned copy |
53 | `app_upgrade_required` | the helper predates the feature or is not running | restart/update the Codewhale Computer Use app |
54 | `unsupported_on_backend` | tool not implemented on that platform backend | check the platform note in the main skill |
55 | `unsupported_on_transport` | `app_script` sent to an ssh/docker/hdc computer — scripting is local-only so a remote channel never becomes a shell | run it on `local`, or use the host's own remote access |
56 | `docker_unavailable` | `computer spawn` found no reachable docker daemon | start Docker (or Colima); spawn needs the daemon, not just the CLI |
57 | `spawn_image_missing` | the requested spawn image is not present locally | build/pull it, or omit `image` to use the plugin's own Linux desktop image (auto-built on first spawn) |
58 | `spawn_failed` | provisioning failed or the desktop did not become ready | read the message; the failed container is removed automatically — fix the cause and spawn again |
59 | `invalid_container` | a docker registry entry lacks a valid container name | register it through `computer spawn`, never by hand |
60 | `cleanup_failed` | `docker rm` failed while tearing down a spawned computer | the registry entry is still removed; check `docker ps` for the labeled container and remove it manually |
61 | `computer_owned_elsewhere` | `computer remove`, `register` or `spawn` named a desktop another session spawned | leave it; its session removes it at exit (the message names the container if that session is gone) |
62 | `script_error` | osascript exited non-zero; stderr is in the message | read the error, check the app's scripting dictionary (`sdef`), fix the script |
63 | `script_timeout` | the script — or a consent dialog — was still open at the deadline | narrow the script; a consent prompt is the person's choice, report it |
64 | `script_cancelled` | the script's own dialog was cancelled (-128) | the user declined in-app; stop or ask |
65 | `automation_denied` | -1743: the responsible app lacks Automation consent for the target | name System Settings → Privacy & Security → Automation; never retry it away |
66 | `permission` / `permissions_denied` | a grant is missing | name the permission and the Settings pane, then stop |
67 | `control_stopped` | the kill switch ended this session | report to the user; the session cannot resume |
68 | `cancelled` | the host cancelled the request | the input may or may not have landed — observe before retrying |
69 | `timeout` | the request exceeded its deadline | observe; only retry after confirming the first attempt did not land |
70
71 `background_focus_required` means this path would borrow keyboard focus and
72 was refused before delivery. Use accessibility, browser control or a separate
73 computer; a typing pause does not authorize foreground control.
74
75 ## Reading a receipt
76
77 - `action_sent` / `verified` mean dispatch (and, where available, read-back) —
78 not task success. Verify the effect with a fresh observation.
79 - `front_lease` / `front_restored` describe focus accounting for window-record
80 deliveries in explicitly authorized foreground mode. `front_restored:false` is a person-visible event: say it out loud.
81 - `outcome_unknown: true` (with `request_dispatched: true`) on an error means
82 the action was already handed to the helper, remote agent or browser when it
83 timed out, was cancelled or lost its reply: observe the target before doing
84 anything else, and never retry the action blindly.
85
85 lines MARKDOWN