Why are my AJAX forms submitted twice? I've been looking up and down for hours now trying to figure out what I am doing wrong. 

Every time I submit a form via AJAX, the submit function gets invoked twice. In other words, the form gets submitted twice. Here is an example I have been working with in my attempt to boil everything down to the basics in hope of finding the root of this very annoying issue (the example assumes AJAX requests, and is not really geared towards graceful degradation).

This is not an issue with multiple AJAX requests being sent from the browser. The browser only sends one single request when i click on the form's 'submit' button.

/**
 * Page callback for 'welcome'. This path has been registered
 * as a plain MENU_CALLBACK.
 */
function us_welcome() {

  // This is where the user arrives at first when navigating to
  // 'welcome'. The user is simply presented with a link which 
  // will load the registration for via AJAX and show that form
  // on the very same page.

  $html[] = l(t('Register'), 'welcome/register/nojs', array(
    'attributes' =&gt; array(
      'class' =&gt; array(
        'use-ajax'
      ),
    ),
  ));

  $html[] = '&lt;div id="form-register-wrapper"&gt;&lt;/div&gt;';

  return implode($html);

}

/**
 * Page callback for 'welcome/register'. This path has been registered
 * as a plain MENU_CALLBACK.
 */
function us_register($mode = 'nojs') {

  // This callback is responsible for the path 'welcome/register'
  // and is the one which the link invokes. If invokation happens
  // from the link, then $mode is 'ajax'. Otherwise, it is 'nojs'.

  // Get form.
  $form = drupal_get_form('us_register_form');

  if ($mode != 'ajax') {
    return $form;
  }

  // Generate commands array.
  $commands = array(
    ajax_command_replace('#form-register-wrapper', drupal_render($form)),
  );

  $page = array('#type' =&gt; 'ajax', '#commands' =&gt; $commands);
  ajax_deliver($page);

}

function us_register_form($form, &amp;$form_state) {

  // A plain old form builder function. Nothing magical
  // going on here.

  $form['#prefix'] = '&lt;div id="form-register-wrapper"&gt;';
  $form['#suffix'] = '&lt;/div&gt;';
  $form['#action'] = '/welcome/register/nojs';

  $form['messages'] = array(
    '#markup' =&gt; '&lt;div id="form-messages"&gt;&lt;/div&gt;',
  );

  $form['basic'] = array(
    '#type' =&gt; 'fieldset',
    '#title' =&gt; t('Basic Details'),
  );

  $form['basic']['name'] = array(
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Your Name'),
  );

  $form['basic']['email'] = array(
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Your E-mail'),
    '#required' =&gt; TRUE,
  );

  $form['basic']['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Submit'),
    '#ajax' =&gt; array(
      'callback' =&gt; 'us_register_form_submit',
      'wrapper' =&gt; 'form-register-wrapper',
      'effect' =&gt; 'fade',
    )
  );

  return $form;

}

function us_register_form_submit($form, &amp;$form_state) {

  // This is the form submit function. The weird thing is that it gets
  // called twice every time the form is submitted via AJAX. 

  // This block of code will only apply to AJAX requests. Normal requests will
  // return from the validation function(s) if validation error(s) should occur,
  // and by the time normal requests get to this point everything have been
  // validated. AJAX requests, on the other hand, goes through the validation
  // function(s) but will still reach this point even though validation error(s)
  // occur. Thus, we need to check for errors and return error messages in case
  // of validation errors. In case of errors, return the form again.
  $errors = form_get_errors();
  if (!empty($errors)) {
    return $form;
  }

  // @todo : carry out registration here.

  $content = array();
  $content[] = t('Thank you for registering!');

  // Process form submission.
  $commands = array(
    ajax_command_replace('#form-register-wrapper', implode($content)),
  );
  $page = array('#type' =&gt; 'ajax', '#commands' =&gt; $commands);
  return $page;
}
The problem you are noticing is caused from the fact that  us_register_form_submit() for Drupal is the form submission handler for the form returned from us_register_form() and, at the same time, you set us_register_form_submit() as AJAX callback.
That function will be called twice, when AJAX is enabled: first as AJAX callback; then, as form submission handler. 

Just change the code as this. (See the /* changed this */ comment.)

  $form['basic']['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Submit'),
    '#ajax' =&gt; array(
      'callback' =&gt; 'us_register_ajax_callback' /* changed this */,
      'wrapper' =&gt; 'form-register-wrapper',
      'effect' =&gt; 'fade',
    )
  );


AJAX callbacks are not for validating a form, and they will never get called to validate a form, except when you set as AJAX callback a function already used as form validation handler. The purpose of an AJAX callback is reacting when a JavaScript event happens for a form field, and updating the form without returning to the browser a full page.