{"record":{"id":"a65fdfa05fedb66e","repo":"Hmbown/CodeWhale","slug":"consent-action-must-be-status-allow-deny-or-revoke-got-json","errorCode":null,"errorMessage":"consent action must be status, allow, deny or revoke (got ${JSON.stringify(args.action)})","messagePattern":"consent action must be status, allow, deny or revoke \\(got (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/tools.mjs","lineNumber":814,"sourceCode":"      if ((args.action === \"stop\" || args.action === \"status\") && rest.id == null) throw bad(`recording action \"${args.action}\" requires id`);\n      return { name: wire, args: rest };\n    }\n    case \"computer\": {\n      const rest = { ...args };\n      delete rest.action;\n      const wire = { list: \"computer_list\", switch: \"computer_switch\", register: \"computer_register\", spawn: \"computer_spawn\", remove: \"computer_remove\" }[args.action];\n      if (!wire) throw bad(`computer action must be list, switch, register, spawn or remove (got ${JSON.stringify(args.action)})`);\n      if (args.action === \"list\") return { name: wire, args: {} };\n      if (rest.id == null) throw bad(`computer action \"${args.action}\" requires id`);\n      const id = rest.id;\n      delete rest.id;\n      return { name: wire, args: { ...rest, computer: id } };\n    }\n    case \"consent\": {\n      const rest = { ...args };\n      delete rest.action;\n      const wire = { status: \"consent_status\", allow: \"consent_allow\", deny: \"consent_deny\", revoke: \"consent_revoke\" }[args.action];\n      if (!wire) throw bad(`consent action must be status, allow, deny or revoke (got ${JSON.stringify(args.action)})`);\n      if (args.action === \"status\") return { name: wire, args: { computer: rest.computer } };\n      const foreground = rest.scope === \"foreground\";\n      if (!foreground && rest.app == null && rest.name == null && rest.bundle_id == null && rest.pid == null) {\n        throw bad(`consent action \"${args.action}\" needs an app (name, bundle_id, pid or app string) — or scope:\"foreground\" for the shared-pointer decision`);\n      }\n      return { name: wire, args: rest };\n    }\n    case \"key\": {\n      if (args.duration == null) return { name, args };\n      const { duration, repeat, target, ...rest } = args;\n      if (repeat != null || target != null) throw bad(\"key with duration holds the key — repeat and target cannot be combined with it\");\n      if (!Number.isFinite(duration) || duration < 0.05 || duration > 30) throw bad(\"duration must be 0.05..30 seconds\");\n      return { name: \"hold_key\", args: { ...rest, duration } };\n    }\n    case \"browser\": {\n      const rest = { ...args };\n      delete rest.action;\n      switch (args.action) {","sourceCodeStart":796,"sourceCodeEnd":832,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/tools.mjs#L796-L832","documentation":"Argument-validation guard in resolveTool for the 'consent' action: args.action matched none of status/allow/deny/revoke in the wire-name map, so the consent request cannot be mapped to a backend command. The bad value is echoed.","triggerScenarios":"resolveTool(\"consent\", { action: \"grant\" }) or { action: \"Allow\" } or {} with no action.","commonSituations":"A model uses \"grant\"/\"block\" instead of allow/deny; missing action; case mismatch.","solutions":["Use one of the four actions: status, allow, deny, revoke","Lowercase the action value","Map \"grant\" to \"allow\" and \"block\" to \"deny\" in caller code"],"exampleFix":"// before\nresolveTool(\"consent\", { action: \"grant\", app: \"Notes\" })\n// after\nresolveTool(\"consent\", { action: \"allow\", app: \"Notes\" })","handlingStrategy":"validation","validationCode":"if (!['status','allow','deny','revoke'].includes(args.action)) throw new Error('consent action must be status/allow/deny/revoke');","typeGuard":"function isConsentAction(a) { return ['status','allow','deny','revoke'].includes(a); }","tryCatchPattern":"try { resolveTool('consent', args); } catch (e) { if (String(e.message).includes('consent action')) { /* map grant->allow, block->deny and retry */ } else throw e; }","preventionTips":["Normalize action casing","Use the four canonical verbs only","Check the schema's action enum before dispatch"],"tags":["validation","enum","consent"],"backgroundTag":"invalid-enum-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}