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

  1. Use one of the supported action names: invoke, click, toggle, expand, expandcollapse, collapse, select (case-insensitive).
  2. Map your action before calling: e.g. 'check' → 'toggle', 'focus' → 'invoke' where semantically valid.
  3. 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

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


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)