Hmbown/CodeWhale · error · ExecError
set_value needs an element target
Error message
set_value needs an element target — {type:'element',index} from get_app_state What it means
set_value writes an accessibility value directly, which only works for element targets backed by the native AX API. If args.target is missing or its type is not 'element', the backend refuses before dispatch — coordinate or key-based targets have no AXValue to set. The intended workflow is to obtain {type:'element',index} from get_app_state.
Solutions
- Call get_app_state, find the field's element entry, and pass { type: 'element', index: el.index } as target.
- Do not pass coordinate targets to set_value — use the focus + select-all + type fallback path (or the advertised replacement action) for controls without AXValue support.
- Validate the target object's shape ({ type: 'element', index: number }) before calling.
Example fix
// before: coordinate target is rejected
await set_value({ target: { type: 'point', x: 120, y: 80 }, value: 'hello' });
// after: element target from a fresh snapshot
const state = await get_app_state();
const field = state.elements.find(e => e.role === 'AXTextField');
await set_value({ target: { type: 'element', index: field.index }, value: 'hello' }); Defensive patterns
Strategy: type-guard
Validate before calling
function assertElementTarget(target) {
if (!target || target.type !== 'element' || !Number.isInteger(target.index)) {
throw new Error("set_value target must be {type:'element',index} from get_app_state");
}
} Type guard
function isElementTarget(t) {
return t != null && t.type === 'element' && Number.isInteger(t.index) && t.index >= 0;
} Try / catch
try {
return await set_value({ target, value });
} catch (e) {
if (String(e.message).includes('set_value needs an element target')) {
const state = await get_app_state();
const el = state.elements.find(e2 => e2.role === 'AXTextField');
return await set_value({ target: { type: 'element', index: el.index }, value });
}
throw e;
} Prevention
- Obtain element targets exclusively from a fresh get_app_state call; never synthesize coordinates for set_value.
- Validate the target shape ({type:'element', index}) before every set_value call.
- For web text controls that ignore AXValue, expect the backend's focus + select-all + type fallback and verify via read-back.
- Re-fetch the snapshot if the element index may have shifted after UI changes.
When it happens
Trigger: Calling set_value with a coordinate target ({type:'point',...}), with no target at all, or with a hand-built target object whose type field is not 'element' instead of the element descriptor returned by get_app_state.
Common situations: Confusing set_value with a type-by-coordinates API; constructing the target from a stale or differently-shaped snapshot; passing the element object itself rather than the {type:'element',index} wrapper the backend expects.
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
- element does not belong to the bound application —…
- element has no resolved accessibility identity
- element press was not acknowledged
- menu_item_not_found
- native accessibility helper needs a built app or Xcode…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/176e0675b03fc20f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/darwin.mjs:1153
for (let i = 0; i < n; i++) {
const press = await withPressedKey(code, flags, () => {});
if (Number.isFinite(press?.yield_ms)) yieldMs = Math.max(yieldMs, press.yield_ms);
if (i < n - 1) await wait(30);
}
return { action_sent: true, key, code, keyboard_delivery: state.foregroundInput ? "foreground-guarded" : "process", repeat: n,
...(yieldMs > 0 ? { yield_ms: yieldMs } : {}),
...(flags !== 0 && !state.foregroundInput ? { note: "process delivery (no focus lease was taken); menu key equivalents can be dropped without a key window. Verify the effect before retrying, or use invoke_menu for app menu commands." } : {}) };
},
hold_key: async ({ text, duration } = {}) => {
const { flags, code, key } = parseChord(text);
if (flags !== 0) requireFocusControl();
const d = Math.max(0.05, Math.min(30, Number(duration) || 1));
const press = await withPressedKey(code, flags, () => wait(d * 1000));
return { action_sent: true, key, keyboard_delivery: state.foregroundInput ? "foreground-guarded" : "process", heldSec: d,
...(Number.isFinite(press?.yield_ms) && press.yield_ms > 0 ? { yield_ms: press.yield_ms } : {}) };
},
set_value: async (args = {}) => {
if (args.target?.type !== "element") throw new ExecError("set_value needs an element target — {type:'element',index} from get_app_state");
try {
return await native("set_value", args);
} catch (error) {
// Web text controls ignore AXValue writes, so the native side refuses
// before dispatch. The replacement path is focus + select-all + type
// with a read-back verify — the same shape kimi-cu uses, with the
// value proven rather than asserted.
if (!/web area/i.test(error.message)) throw error;
if (args.target?.type !== "element") throw error;
requireFocusControl();
const value = String(args.value ?? "");
await native("focus_element", { target: args.target });
// cmd+a through the record channel: menu key equivalents only
// validate against a key window, which the lease provides. bg_key
// posts a complete press (down and up); the `down` field is unused.
await native("bg_key", { code: 0, flags: 1 << 20 });
await new Promise((r) => setTimeout(r, 60));
await native("type", { text: value });View on GitHub (pinned to 73e0f67d83)