Hmbown/CodeWhale · error · NSException

invalid request

Error message

invalid request

What it means

The macOS accessibility computer-use backend is a helper binary that expects exactly one JSON argument and parses it with NSJSONSerialization. If the argument parses to something other than an NSDictionary (the top-level JSON object), the helper throws an 'invalid request' exception and fails instead of executing a command.

Solutions

  1. Pass exactly one argument containing the JSON request object, properly shell-quoted
  2. Ensure the JSON root is an object ({...}), not an array or scalar
  3. Rebuild/reinstall the native helper so binary and caller agree on the request format
  4. Test with a minimal payload like '{"args":{}}' to confirm the invocation works

Example fix

// before: unquoted / wrong shape
bin/darwin-accessibility args action=click

// after: one quoted JSON object argument
bin/darwin-accessibility '{"args":{"action":"click","x":100,"y":200}}'
Defensive patterns

Strategy: validation

Validate before calling

function assertDarwinRequest(req) {
  if (typeof req !== 'object' || req === null || Array.isArray(req))
    throw new Error('darwin-accessibility request must be a JSON object');
}
// invocation: spawn(bin, [JSON.stringify(req)], ...) — one argument, always an object root

Type guard

const isRequestObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);

Try / catch

try {
  const out = execFileSync(bin, [JSON.stringify(req)], { encoding: 'utf8' });
} catch (e) {
  if (String(e.stderr || e.message).includes('invalid request')) {
    // payload was not a single JSON object argument; fix invocation and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Launching darwin-accessibility with zero, multiple, or malformed command-line arguments; passing JSON whose root is an array, string, or number instead of an object (argc!=2 raises the earlier 'args' exception; a non-dictionary root raises this one at line 840).

Common situations: Invoking the helper manually from a shell without quoting the JSON (shell splitting turns one arg into many); a caller passing JSON built with the wrong top-level shape; an old native binary being driven by a newer TUI that changed the request schema; quoting bugs that mangle the JSON payload.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/dc4c5b6cd70d8f92. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/backends/darwin-accessibility.m:840

    else if([tool isEqual:@"focus_element"]) e=AXUIElementSetAttributeValue((__bridge AXUIElementRef)el,kAXFocusedAttribute,kCFBooleanTrue);
    else if([tool isEqual:@"select_text"]){ NSArray *r=args[@"text_range"]?:@[@0,@0]; if(r.count!=2 || [r[0] longValue]<0 || [r[1] longValue]<0) @throw [NSException exceptionWithName:@"range" reason:@"text_range must be [start, length], both nonnegative" userInfo:nil]; CFRange range=CFRangeMake([r[0] longValue],[r[1] longValue]); AXValueRef v=AXValueCreate(kAXValueCFRangeType,&range); e=AXUIElementSetAttributeValue((__bridge AXUIElementRef)el,kAXSelectedTextRangeAttribute,v); CFRelease(v); }
    else if([tool isEqual:@"perform_action"]){ CFArrayRef actions=NULL; AXUIElementCopyActionNames((__bridge AXUIElementRef)el,&actions); NSArray *names=CFBridgingRelease(actions); if(![names containsObject:args[@"action"]]) @throw [NSException exceptionWithName:@"action" reason:@"action is not advertised by this element" userInfo:nil]; cuCheckCancelled(); e=AXUIElementPerformAction((__bridge AXUIElementRef)el,(__bridge CFStringRef)args[@"action"]); }
    if(e!=kAXErrorSuccess) @throw [NSException exceptionWithName:@"action" reason:[NSString stringWithFormat:@"accessibility action failed: %d",e] userInfo:nil];
    NSMutableDictionary *done=[@{@"action_sent":@YES,@"strategy":@"a11y"} mutableCopy];
    if([tool isEqual:@"focus_element"]) done[@"focused"]=@YES;
    if([tool isEqual:@"set_value"]) {
      id after=attr((__bridge AXUIElementRef)el,@"AXValue");
      done[@"after"]=after?:[NSNull null];
      done[@"verified"]=@([after isKindOfClass:NSString.class] && [after isEqual:args[@"value"]]);
    }
    return done;
  } @finally { CFRelease(app); }
}
int main(int argc, const char **argv){ @autoreleasepool {
  signal(SIGTERM,cuCancel); signal(SIGINT,cuCancel); signal(SIGPIPE,SIG_IGN);
  @try { if(argc!=2) @throw [NSException exceptionWithName:@"args" reason:@"expected one JSON argument" userInfo:nil];
    NSError *error=nil; id p=[NSJSONSerialization JSONObjectWithData:[[NSString stringWithUTF8String:argv[1]] dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
    if(![p isKindOfClass:NSDictionary.class]) @throw [NSException exceptionWithName:@"json" reason:@"invalid request" userInfo:nil];
    id result=execute(p);
    if([p[@"args"][@"input_lease"] boolValue]) { NSMutableDictionary *ack=[result mutableCopy]; ack[@"input_lease"]=@YES; result=ack; }
    NSData *data=[NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingFragmentsAllowed error:&error];
    if(!data) @throw [NSException exceptionWithName:@"json" reason:error.localizedDescription userInfo:nil];
    puts([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding].UTF8String); fflush(stdout);
    if([p[@"args"][@"input_lease"] boolValue]) cuWaitForLease();
    return 0;
  } @catch(NSException *e){ cuReleaseLease(); fprintf(stderr,"%s\n",e.reason.UTF8String); return 1; }
} }

View on GitHub (pinned to 433685b202)