#autocomplete_path doesn't present a "spinny thing" I'm working on adding an autocomplete field to a node edit form using hook_form. The field should not be stored in the database; hence the reason I am not adding a field to the node itself.

I seem to have the required components for autocomplete to work, and I've double checked spelling errors, but I can't get a "spinny thing" (aka "throbber") to appear, and there are no attempts by the browser to retrieve data from the autocomplete path when entering data into the autocomplete field.

Javascript is working in the browser, as evidenced by a working entity reference autocomplete field.

Some code:

/**
 * Implements hook_menu()
 */
function cao_contenttypes_menu() {
    $items = array();

    // autocomplete
    $items['cao_contenttypes/user/autocomplete/%'] = array(
        'title'            =&gt; 'Autocomplete C&amp;O users',
        'page callback'    =&gt; 'cao_contenttypes_cao_handler_users_autocomplete',
        'page arguments'   =&gt; array(3),
        'access arguments' =&gt; array('C&amp;O Administrator'),
        'type'             =&gt; MENU_CALLBACK,
    );

    return $items;
}


/**
 * Implements hook_form()
 */
function cao_handler_form($node, $form_state) {
    // Fields in the node add form are merged into the array we create
    // here.
    global $user;

    // Fetch the title field.
    $form = node_content_form($node, $form_state);

    // get a list of users that are allowed to have cao
    $users = _cao_contenttypes_cao_handler_users();
    $form['c__o_user'] = array(
        '#type' =&gt; 'select',
        '#title' =&gt; 'CaO User',
        '#weight' =&gt; -20,
        '#description' =&gt; 'Choose a user.',
    );

    if (0 &lt; count($users)) {
        dpm($users, 'users');
        $form['c__o_user']['#type'] = 'textfield';
        $form['c__o_user']['#autocomplete_path'] = 'cao_contenttypes/user/autocomplete';
    } else {
        $form['c__o_user']['#options'] = array();
    }

    return $form;
}

function cao_contenttypes_cao_handler_users_autocomplete($str) {
    if (!$str) {
        return;
    }

    // choose users from among a limited subset
    $users = _cao_contenttypes_cao_handler_users();
    $list = array();
    array_walk($users, function ($item) use ($str, &amp;$list) {
        $comp = substr($item-&gt;name, 0, strlen($str));
        if ($comp == $str) {
            $list[] = $item-&gt;name;
        }
    });
    drupal_json_output($list);
}
What you should do is change $item inside your menu() hook to be

$items['cao_contenttypes/user/autocomplete'] = array(
    'title'            =&gt; 'Autocomplete C&amp;O users',
    'page callback'    =&gt; 'cao_contenttypes_ceao_handler_users_autocomplete',
    'access arguments' =&gt; array('C&amp;O Administrator'),
    'type'             =&gt; MENU_CALLBACK,
);


eg, remove the trailing % (Drupal will add in the string for you just fine when it has one) and then inside your callback do something like this:

function cao_contenttypes_cao_handler_users_autocomplete($str='') {

  $list = array();
  if ($str) {
    // choose users from among a limited subset
    $users = _cao_contenttypes_cao_handler_users();
    array_walk($users, function ($item) use ($str, &amp;$list) {
      $comp = substr($item-&gt;name, 0, strlen($str));
      if ($comp == $str) {
        $list[] = $item-&gt;name;
      }
    });
  }

  drupal_json_output($list);

}


eg, give $str a default value and always return the array of results, even if empty.

Additional comment:  Consider cache()ing the output of _cao_contenttypes_cao_handler_users() if it is a heavyweight function.