Hmbown/CodeWhale · error
consent action " " needs an app (name, bundle_id, pid or…
Error message
consent action "${args.action}" needs an app (name, bundle_id, pid or app string) — or scope:"foreground" for the shared-pointer decision What it means
For consent actions allow/deny/revoke, the target app must be identified: either scope:"foreground" (the shared-pointer decision) or one of app, name, bundle_id, or pid. When none is supplied the resolver throws this descriptive error rather than sending an untargeted consent change.
Solutions
- Add the target app identification: app (string), name, bundle_id, or pid
- Set scope:"foreground" if the decision applies to the foreground/shared-pointer app
- Fix scope casing to lowercase "foreground" if that was the intent
Example fix
// before
resolveTool("consent", { action: "deny", scope: "Foreground" })
// after
resolveTool("consent", { action: "deny", scope: "foreground" }) // or add app: "Notes" Defensive patterns
Strategy: validation
Validate before calling
function consentTargeted(a) {
if (a.action === 'status') return true;
return a.scope === 'foreground' || a.app != null || a.name != null || a.bundle_id != null || a.pid != null;
}
if (!consentTargeted(args)) throw new Error('consent allow/deny/revoke needs app or scope:"foreground"'); Type guard
function hasConsentTarget(a) { return ['app','name','bundle_id','pid'].some(k => a[k] != null) || a.scope === 'foreground'; } Try / catch
try { resolveTool('consent', args); } catch (e) { if (String(e.message).includes('needs an app')) { /* prompt for target app or set scope:'foreground' */ } else throw e; } Prevention
- Always identify the app (name/bundle_id/pid) or explicitly set scope:"foreground" (lowercase)
- Remember consent changes are per-app; there is no global grant
- Keep app identification fields at the top level of args
When it happens
Trigger: resolveTool("consent", { action: "allow" }) with no app/name/bundle_id/pid and scope not "foreground"; scope misspelled as e.g. "active" so the foreground shortcut is not taken.
Common situations: A model wants to grant consent globally without naming an app (unsupported); scope:"Foreground" wrong case so it is not recognized; the app fields are put under a nested object instead of top-level.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- clipboard action "write" requires text
- computer action " " requires id
- consent action must be status, allow, deny or revoke
- custom theme requires custom_theme_name
- external credential consent is scoped to provider
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d47f0a116a3a5516.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/tools.mjs:818
const rest = { ...args };
delete rest.action;
const wire = { list: "computer_list", switch: "computer_switch", register: "computer_register", spawn: "computer_spawn", remove: "computer_remove" }[args.action];
if (!wire) throw bad(`computer action must be list, switch, register, spawn or remove (got ${JSON.stringify(args.action)})`);
if (args.action === "list") return { name: wire, args: {} };
if (rest.id == null) throw bad(`computer action "${args.action}" requires id`);
const id = rest.id;
delete rest.id;
return { name: wire, args: { ...rest, computer: id } };
}
case "consent": {
const rest = { ...args };
delete rest.action;
const wire = { status: "consent_status", allow: "consent_allow", deny: "consent_deny", revoke: "consent_revoke" }[args.action];
if (!wire) throw bad(`consent action must be status, allow, deny or revoke (got ${JSON.stringify(args.action)})`);
if (args.action === "status") return { name: wire, args: { computer: rest.computer } };
const foreground = rest.scope === "foreground";
if (!foreground && rest.app == null && rest.name == null && rest.bundle_id == null && rest.pid == null) {
throw bad(`consent action "${args.action}" needs an app (name, bundle_id, pid or app string) — or scope:"foreground" for the shared-pointer decision`);
}
return { name: wire, args: rest };
}
case "key": {
if (args.duration == null) return { name, args };
const { duration, repeat, target, ...rest } = args;
if (repeat != null || target != null) throw bad("key with duration holds the key — repeat and target cannot be combined with it");
if (!Number.isFinite(duration) || duration < 0.05 || duration > 30) throw bad("duration must be 0.05..30 seconds");
return { name: "hold_key", args: { ...rest, duration } };
}
case "browser": {
const rest = { ...args };
delete rest.action;
switch (args.action) {
case "start":
if (rest.url != null && typeof rest.url !== "string") throw bad("browser start url must be a string");
return { name: "browser_start", args: rest };
case "status": return { name: "browser_status", args: rest };View on GitHub (pinned to 73e0f67d83)