Hmbown/CodeWhale · error · ExecError
unsupported UIA action
Error message
unsupported UIA action
What it means
perform_action on the win32 backend maps a whitelisted action name (invoke, click, toggle, expand, collapse, select, and case variants) onto UI Automation patterns. Any other string — or a misspelling — fails this lookup and throws. It is an input validation error on the action parameter.
Solutions
- Use one of the supported action names: invoke, click, toggle, expand, expandcollapse, collapse, select (case-insensitive).
- Map your action before calling: e.g. 'check' → 'toggle', 'focus' → 'invoke' where semantically valid.
- Validate action strings against the supported list before dispatching to avoid wasted 45s PowerShell calls.
Example fix
// before
await backend.perform_action({ target, action: 'check' }); // throws
// after
const supported = ['invoke','click','toggle','expand','expandcollapse','collapse','select'];
const act = supported.includes(String(action).toLowerCase()) ? action : 'toggle';
await backend.perform_action({ target, action: act }); Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED_UIA_ACTIONS = ['invoke','click','toggle','expand','expandcollapse','collapse','select'];
function assertUiaAction(action) {
if (!SUPPORTED_UIA_ACTIONS.includes(String(action).toLowerCase()))
throw new Error(`unsupported UIA action: ${action}`);
} Type guard
const isSupportedAction = (a) => ['invoke','click','toggle','expand','expandcollapse','collapse','select'] .includes(String(a).toLowerCase());
Try / catch
try {
await backend.perform_action({ target, action });
} catch (e) {
if (e.message === 'unsupported UIA action') throw new Error(`action ${action} not supported on win32; use invoke/toggle/expand/collapse/select`);
throw e;
} Prevention
- Normalize and whitelist action names before dispatching to perform_action.
- Map cross-backend action vocabularies (check→toggle, focus→invoke) explicitly.
- Never pass raw UIA pattern names as the action string.
- Unit-test the action-name mapping used by your agent scripts.
When it happens
Trigger: Calling perform_action with action set to anything outside the mapping, e.g. 'check', 'focus', 'ExpandCollapse', 'scroll', or a typo like 'invke'; also when action is a non-string that String()ifies to an unmapped value.
Common situations: Scripts written against another backend's richer action vocabulary (e.g. check/uncheck or focus actions) being reused on win32; case/spacing mistakes; passing the UIA pattern name instead of the logical action name.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Windows get_app_state supports only app_ref
- application window not found in UIA tree — pass…
- coordinates must be finite numbers
- display index is out of range
- late usage store must be a real directory
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/7889dded3688e23a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:552
},
set_value: async ({ target, value }) => {
const resolve = elementScript(target);
const b64 = Buffer.from(String(value ?? ""), "utf16le").toString("base64");
const j = await psJson(`${resolve}
$val = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${b64}'));
$vp = $cur.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern);
if ($vp.Current.IsReadOnly) { throw 'element_read_only' }
$vp.SetValue($val);
@{ ok = $true; verified = ($vp.Current.Value -ceq $val) } | ConvertTo-Json -Compress;`, { timeoutMs: 45_000 });
if (!j.ok) throw new ExecError("set_value failed");
return { action_sent: true, strategy: "a11y", verified: j.verified === true };
},
select_text: async () => { throw new ExecError("select_text is not implemented on the win32 backend yet — fail-closed"); },
perform_action: async ({ target, action = "Invoke" }) => {
const resolve = elementScript(target);
const actions = { invoke: ["Invoke", "Invoke"], click: ["Invoke", "Invoke"], toggle: ["Toggle", "Toggle"], expand: ["ExpandCollapse", "Expand"], expandcollapse: ["ExpandCollapse", "Expand"], collapse: ["ExpandCollapse", "Collapse"], select: ["SelectionItem", "Select"], selectionitem: ["SelectionItem", "Select"] };
const chosen = actions[String(action).toLowerCase()];
if (!chosen) throw new ExecError("unsupported UIA action");
await psOk(`${resolve}
$pattern = $cur.GetCurrentPattern([System.Windows.Automation.${chosen[0]}Pattern]::Pattern);
$pattern.${chosen[1]}();`, { timeoutMs: 45_000 });
return { action_sent: true, strategy: "a11y", action };
},
read_clipboard: async () => {
const j = await psJson(`$t = Get-Clipboard -Raw -ErrorAction SilentlyContinue;
@{ text = [string]$t } | ConvertTo-Json -Compress;`, { timeoutMs: 10_000 });
return { text: j.text ?? "", encoding: "utf8" };
},
write_clipboard: async ({ text }) => {
const b64 = Buffer.from(String(text ?? ""), "utf16le").toString("base64");
await psOk(`Set-Clipboard -Value ([System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${b64}')));
Write-Output '{"ok": true}';`, { timeoutMs: 10_000 });
return { written: String(text ?? "").length };
},
cursor_position: async () => {
const j = await psJson(`${USER32_PRELUDE}View on GitHub (pinned to 73e0f67d83)