Hmbown/CodeWhale · error

Windows get_app_state supports only app_ref

Error message

Windows get_app_state supports only app_ref: { name: exact window title }; PID, bundle_id and other references are unsupported

What it means

Windows get_app_state accepts only app_ref: { name: "exact window title" }. Any other app_ref shape — pid, bundle_id, extra keys, non-object, empty/blank name, or an array — throws unsupportedSelector, because the UIA lookup filters windows purely by title.

Solutions

  1. Pass exactly app_ref: { name: <exact window title> } with a non-empty trimmed string.
  2. Copy the title verbatim from list_windows (win.title) or list_apps (apps[].title).
  3. Do not include pid, bundle_id, or any second key in the app_ref object.
  4. Match the app another way if only the pid is known: run list_windows and match the process name, then use its title.

Example fix

// before
await computerUse({ action: "get_app_state", app_ref: { pid: 1234 } });
// after
await computerUse({ action: "get_app_state", app_ref: { name: "Untitled - Notepad" } });
Defensive patterns

Strategy: type-guard

Validate before calling

const ok = args?.app_ref && !Array.isArray(args.app_ref) && Object.keys(args.app_ref).length === 1 && typeof args.app_ref.name === "string" && args.app_ref.name.trim();

Type guard

function isTitleAppRef(a) { return !!a && typeof a === "object" && !Array.isArray(a) && Object.keys(a).length === 1 && "name" in a && typeof a.name === "string" && a.name.trim().length > 0; }

Try / catch

try { await getAppState(args) } catch (e) { if (String(e.message).includes("supports only app_ref")) { args.app_ref = { name: await resolveWindowTitle(args) }; await getAppState(args); } else throw e; }

Prevention

When it happens

Trigger: app_ref missing, not an object, an array, containing keys other than name, name not a string, or name blank/whitespace; or passing { pid } / { bundle_id } forms valid on other backends.

Common situations: Reusing macOS-style { bundle_id } references on Windows; passing a process pid from list_apps instead of the window title; constructing app_ref programmatically and emitting an empty name.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/8ae0373ba04c56d1. Report an issue: GitHub.

Appendix: source

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

        // one argument there, and transport that string as data into PowerShell.
        const quoted = '"' + urlArg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, '$1$1') + '"';
        const encoded = Buffer.from(quoted, "utf16le").toString("base64");
        argumentsScript = `$launchArg = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${encoded}')); `;
      }
      // activate defaults to background on every platform: a minimized
      // launch leaves the user's foreground window alone. Windows input is
      // still shared-surface — this only controls the launch, not input.
      const windowStyle = activate === true ? "" : " -WindowStyle Minimized";
      const r = await psOk(`${argumentsScript}Start-Process -FilePath "${target}"${windowStyle}${urlArg != null ? " -ArgumentList $launchArg" : ""}; Write-Output '{"launched": true}'`, { timeoutMs: 20_000 });
      if (r.code !== 0) throw new ExecError(`Start-Process failed: ${r.stderr.trim().slice(0, 200)}`, r);
      return { launched: true, name: target, url: urlArg ?? null, activate: activate === true };
    },
    get_app_state: async (args = {}) => {
      if (Object.hasOwn(args, "window_id")) throw unsupportedSelector("Windows get_app_state does not support window_id");
      const { app_ref, detail } = args;
      if (Object.hasOwn(args, "app_ref") && (!app_ref || typeof app_ref !== "object" || Array.isArray(app_ref)
        || Object.keys(app_ref).length !== 1 || !Object.hasOwn(app_ref, "name") || typeof app_ref.name !== "string" || !app_ref.name.trim())) {
        throw unsupportedSelector("Windows get_app_state supports only app_ref: { name: exact window title }; PID, bundle_id and other references are unsupported");
      }
      const filter = Buffer.from(app_ref?.name ?? "", "utf16le").toString("base64");
      const maxEls = detail === "full" ? 800 : 400;
      const j = await psJson(`${UIA_PRELUDE}
$max = ${maxEls};
$filter = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${filter}'));
$root = [System.Windows.Automation.AutomationElement]::RootElement;
$els = New-Object System.Collections.ArrayList;
$found = $false; $truncated = $false; $appName = $null;
$targets = @($root.FindAll([System.Windows.Automation.TreeScope]::Children, [System.Windows.Automation.Condition]::TrueCondition));
if ($filter) {
  $targets = @($targets | Where-Object { [string]::Equals($_.Current.Name, $filter, [StringComparison]::OrdinalIgnoreCase) });
  if ($targets.Count -gt 1) { throw 'More than one application window has this exact name' }
}
foreach ($t in $targets) {
  $nm = $t.Current.Name;
  $found = $true; $appName = $nm;
  $stack = New-Object System.Collections.Stack;

View on GitHub (pinned to 73e0f67d83)