Hmbown/CodeWhale · error · ExecError

native helper needs an update for element identity…

Error message

native helper needs an update for element identity validation

What it means

Inside the a11y click path, after assertBoundElement passes, the backend asks the native helper for input_capabilities and requires element_identity === 1 — proof that the helper can validate that a stored element reference still maps to the same UI element before pressing it. An older native helper without element-identity support cannot offer that safety, so the backend refuses rather than clicking a possibly-stale target.

Solutions

  1. Rebuild/reinstall the native macOS helper to match the plugin version that declares element_identity support.
  2. Verify with input_capabilities that element_identity === 1 before retrying the click.
  3. Clear cached helper binaries so the current version is launched.
  4. Temporarily fall back to a coordinate/event strategy (e.g. pointerClick with strategy 'event') if stale-element risk is acceptable.
Defensive patterns

Strategy: validation

Validate before calling

const caps = await native('input_capabilities');
if (caps?.element_identity !== 1) {
  throw new Error('native helper lacks element identity validation');
}
await session.left_click({ target: boundElement, strategy: 'a11y' });

Type guard

const supportsElementIdentity = (caps) => caps?.element_identity === 1;

Try / catch

try {
  await session.left_click({ target: element, strategy: 'a11y' });
} catch (e) {
  if (String(e.message).includes('native helper needs an update')) {
    await reinstallNativeHelper();
    return session.left_click({ target: element, strategy: 'a11y' });
  } else throw e;
}

Prevention

When it happens

Trigger: left_click (or the sibling element-action paths) with a bound element target on macOS when the installed native helper's input_capabilities.element_identity is not 1 — outdated helper binary or version mismatch with the JS plugin.

Common situations: Package upgrade without rebuilding the native helper; a stale cached helper; running a helper built before the element-identity feature landed.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/backends/darwin.mjs:1005

    },
    resolve_element: async ({ app_ref, windowIndex, path: pathArr } = {}) => {
      const r = await native("resolve_element", { app_ref, windowIndex: windowIndex ?? 0, path: pathArr ?? [] });
      return { found: !!r?.found, element: r?.element ?? null, reason: r?.reason ?? null };
    },
    preview: async ({ enabled = true } = {}) => {
      state.previewEnabled = enabled;
      if (!enabled) { stopPreviewLoop(); await quiescePreview(); await native("preview_notify", { enabled: false }); return { enabled: false }; }
      if (!state.inputApp) throw new ExecError("open_application first to choose the preview app");
      return updatePreview(true);
    },
    screenshot,
    zoom,
    left_click: async ({ target, strategy = "auto" } = {}) => {
      if (target?.type !== "element" || strategy === "event" || strategy === "app") return pointerClick("left", target?.x, target?.y, 1, strategy);
      if (!["auto", "a11y"].includes(strategy)) throw new ExecError(`strategy must be auto, a11y, app or event (got ${JSON.stringify(strategy)})`);
      try {
        assertBoundElement(target);
        if ((await native("input_capabilities"))?.element_identity !== 1) throw new ExecError("native helper needs an update for element identity validation");
        const semantic = ["AXTextField", "AXTextArea", "AXComboBox", "AXRow", "AXCell", "AXMenuItem"].includes(target.role);
        if (semantic) await requireBackgroundActions();
        const receipt = await native(semantic ? "click_element" : "perform_action", { target, action: "AXPress" });
        if (!receipt?.action_sent) throw new ExecError("element press was not acknowledged");
        return { ...receipt, action: receipt.action ?? "AXPress", strategy: "a11y", pointer_moved: false,
          element: { role: target.role, label: target.label ?? null }, verified: receipt.verified ?? false, verification_required: "observation" };
      } catch (error) {
        // An AX frame can cover other controls. Never turn a refused or
        // ambiguous element press into another element's press or a raw click.
        error.message += ' — no coordinate fallback was sent; take a fresh screenshot or OCR observation and choose an advertised action or a separate computer';
        throw error;
      }
    },
    double_click: ({ target } = {}) => pointerClick("left", target?.x, target?.y, 2),
    triple_click: ({ target } = {}) => pointerClick("left", target?.x, target?.y, 3),
    right_click: async ({ target } = {}) => {
      if (target?.type !== "element") return pointerClick("right", target?.x, target?.y, 1);
      assertBoundElement(target);

View on GitHub (pinned to 73e0f67d83)