Hmbown/CodeWhale · error · ExecError

set_value failed

Error message

set_value failed: ${j.code}

What it means

set_value on the win32 backend drives a UI element through UI Automation's ValuePattern via a PowerShell script. The script itself catches any .NET exception inside PowerShell and emits {ok:false, code:"<exception message>"} instead of crashing; the Node layer then throws ExecError('set_value failed: <code>'). The <code> is therefore the raw UIAutomation exception message (e.g. element no longer exists, pattern unsupported, value rejected by the control).

Solutions

  1. Read the code embedded in the message: 'Unsupported Pattern' / null-pattern means the control has no ValuePattern — use keyboard input (type into the focused element) instead of a11y set_value.
  2. Re-acquire the accessibility tree snapshot immediately before set_value so the element path is fresh; retry once with the new path if the message indicates the element is gone.
  3. Confirm the target control is enabled and not read-only (inspect via the a11y snapshot's element properties).
  4. If the target app's UI thread is hung (timeout-flavored message), unblock or restart the app, then retry.
  5. Fall back to an event strategy: focus the element (click) and send the text as keystrokes, which works for controls without ValuePattern.

Example fix

// before
await backend.set_value({ target: staleTarget, value: "hello" });
// after
const fresh = await backend.accessibility_tree(); // re-snapshot
const target = findMatchingElement(fresh, staleTarget);
if (!target) throw new Error('element vanished; re-locate before set_value');
await backend.set_value({ target, value: "hello" });
Defensive patterns

Strategy: try-catch

Validate before calling

function canSetValue(elementSnapshot) {
  return elementSnapshot &&
    Array.isArray(elementSnapshot.path) && elementSnapshot.path.length > 0 &&
    !elementSnapshot.readOnly && elementSnapshot.enabled !== false &&
    (elementSnapshot.patterns ?? []).includes("ValuePattern");
}

Type guard

function isElementTarget(t) {
  return t != null && typeof t === "object" && Array.isArray(t.path) && t.path.length > 0;
}

Try / catch

try {
  await backend.set_value({ target, value });
} catch (e) {
  if (e instanceof ExecError && e.message.startsWith("set_value failed:")) {
    // refresh the tree and retry once; fall back to keystrokes
    const fresh = await refreshTarget(target);
    if (fresh) return backend.set_value({ target: fresh, value });
    return typeViaKeyboard(value); // controls without ValuePattern
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling set_value({ target, value }) on the win32 backend when: the resolved UIA element does not support ValuePattern ($vp is null so SetValue is called on null), the element has disappeared or its UIA runtime id path is stale, the control rejects the value (read-only field, validation), or the element is in a non-value-able state.

Common situations: Targeting a stale element snapshot taken before the UI re-rendered (dialog closed, list re-populated); attempting to type into a custom-drawn control (canvas, browser canvas widgets) that exposes no ValuePattern; setting a value on a read-only or disabled edit box; 45-second timeout expiring because the target app's UI thread is blocked (UIA calls are synchronous with the target process).

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/502a518f6c614769. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:487

$val = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${b64val}'));
$indices = $textPath | ConvertFrom-Json;
$root = [System.Windows.Automation.AutomationElement]::RootElement;
$targets = $root.FindAll([System.Windows.Automation.TreeScope]::Children, [System.Windows.Automation.Condition]::TrueCondition);
$cur = $null;
foreach ($t in $targets) { $cur = $t; break }
if ($cur -eq $null) { Write-Output '{"ok": false, "code": "app_not_found"}'; exit 0 }
foreach ($i in $indices) {
  if ($i -eq 0) { continue }
  $kids = $cur.FindAll([System.Windows.Automation.TreeScope]::Children, [System.Windows.Automation.Condition]::TrueCondition);
  if ($i -ge $kids.Count) { Write-Output '{"ok": false, "code": "element_stale"}'; exit 0 }
  $cur = $kids[$i];
}
try {
  $vp = $cur.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern);
  $vp.SetValue($val);
  Write-Output '{"ok": true}';
} catch { Write-Output ('{"ok": false, "code": "' + $_.Exception.Message.Replace('"','') + '"}') }`, { timeoutMs: 45_000 });
      if (!j.ok) throw new ExecError(`set_value failed: ${j.code}`);
      return { action_sent: true, strategy: "a11y" };
    },
    select_text: async () => { throw new ExecError("select_text is not implemented on the win32 backend yet — fail-closed"); },
    perform_action: async ({ target, action }) => {
      assertUntargetedElement(target);
      const b64path = Buffer.from(JSON.stringify(target.path ?? []), "utf8").toString("base64");
      const act = String(action ?? "Invoke").replace(/'/g, "");
      const j = await psJson(`Add-Type -AssemblyName UIAutomationClient; Add-Type -AssemblyName UIAutomationTypes;
$path = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${b64path}'));
$indices = $path | ConvertFrom-Json;
$root = [System.Windows.Automation.AutomationElement]::RootElement;
$targets = $root.FindAll([System.Windows.Automation.TreeScope]::Children, [System.Windows.Automation.Condition]::TrueCondition);
$cur = $null;
foreach ($t in $targets) { $cur = $t; break }
foreach ($i in $indices) {
  if ($i -eq 0) { continue }
  $kids = $cur.FindAll([System.Windows.Automation.TreeScope]::Children, [System.Windows.Automation.Condition]::TrueCondition);
  if ($i -ge $kids.Count) { Write-Output '{"ok": false, "code": "element_stale"}'; exit 0 }

View on GitHub (pinned to 433685b202)