=== modified file 'includes/form.inc'
--- includes/form.inc	2009-03-30 03:15:40 +0000
+++ includes/form.inc	2009-04-05 04:52:20 +0000
@@ -208,7 +208,7 @@ function drupal_build_form($form_id, &$f
   // the form, passing in the latest $form_state in addition to any
   // other variables passed into drupal_get_form().
 
-  if (!empty($form_state['rebuild']) || !empty($form_state['storage'])) {
+  if (!form_get_errors() && (!empty($form_state['rebuild']) || !empty($form_state['storage']))) {
     $form = drupal_rebuild_form($form_id, $form_state);
   }
 

=== modified file 'modules/node/node.test'
--- modules/node/node.test	2009-03-31 01:49:50 +0000
+++ modules/node/node.test	2009-04-05 04:54:20 +0000
@@ -637,3 +637,39 @@ class NodeRSSContentTestCase extends Dru
     $this->assertText($test_text, t('Extra node content appears in RSS feed.'));
   }
 }
+
+class TwoStepNodeTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Two step node'),
+      'description' => t('Test that two step nodes keep their taxonomy.'),
+      'group' => t('Node')
+    );
+  }
+
+  function setUp() {
+    parent::setUp('taxonomy', 'twostepnode');
+  }
+
+  function testTwoStepNode() {
+    $this->account = $this->drupalCreateUser(array('create twostepnode content'));
+    $this->drupalLogin($this->account);
+    // Create a vocabulary.
+    $vocabulary = new stdClass();
+    $vocabulary->name = $this->randomName();
+    $vocabulary->nodes = array('twostepnode' => 'twostepnode');
+    taxonomy_vocabulary_save($vocabulary);
+    $term = new stdClass();
+    $term->name = $this->randomName();
+    $term->vid = $vocabulary->vid;
+    taxonomy_term_save($term);
+    $title = $this->randomName();
+    $edit = array('title' => $title);
+    $this->drupalPost('node/add/twostepnode', $edit, t('Next'));
+    $edit = array("taxonomy[$term->vid]" => $term->tid);
+    $this->drupalPost(NULL, $edit, t('Preview'));
+    $this->assertText(t('Required body field is required.'), t('Error present'));
+    $options = $this->xpath('//option[@value="'. $term->tid .'"]');
+    $this->assertTrue($options[0]['selected'] == 'selected', t('Term still selected'));
+  }
+}

=== added file 'modules/node/tests/twostepnode.info'
--- modules/node/tests/twostepnode.info	1970-01-01 00:00:00 +0000
+++ modules/node/tests/twostepnode.info	2009-04-05 04:13:54 +0000
@@ -0,0 +1,6 @@
+; $Id$
+name = Two step node
+description = Provides a node type with a 2-step form for testing.
+core = 7.x
+files[] = twostepnode.module
+hidden = TRUE

=== added file 'modules/node/tests/twostepnode.module'
--- modules/node/tests/twostepnode.module	1970-01-01 00:00:00 +0000
+++ modules/node/tests/twostepnode.module	2009-04-05 04:51:38 +0000
@@ -0,0 +1,130 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Provides a node type with a multi-step node form for testing.
+ */
+
+/**
+ * Implementation of hook_node_info().
+ */
+function twostepnode_node_info() {
+  return array(
+    'twostepnode' => array(
+      'name' => t('2-step node'),
+      'base' => 'twostepnode',
+      'description' => t('A node that uses a multi-step node form for testing.'),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_perm.
+ */
+function twostepnode_perm() {
+  return node_list_permissions('twostepnode');
+}
+
+/**
+ * Implementation of hook_access.
+ */
+function twostepnode_access($op, $node, $account) {
+  global $user;
+  switch ($op) {
+    case 'create':
+      return user_access('create twostepnode content', $account);
+    case 'update':
+      return user_access('edit any twostepnode content', $account) || (user_access('edit own twostepnode content', $account) && ($node->uid == $account->uid));
+    case 'delete':
+      return user_access('delete any twostepnode content', $account) || (user_access('delete own twostepnode content', $account) && ($node->uid == $account->uid));
+  }
+}
+
+/**
+ * Implementation of hook_form().
+ */
+function twostepnode_form($node, $form_state) {
+  $form['title'] = array(
+    '#title' => t('Title'),
+    '#type' => 'textfield',
+    '#required' => TRUE,
+    '#default_value' => isset($form_state['storage']['title']) ? $form_state['storage']['title'] : $node->title,
+  );
+  $form['body_field'] = node_body_field($node, t('Required body'), 1);
+  return $form;
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * When first adding the node, put the 'Title' field on its own page in a
+ * multistep node form.  We need to do this in hook_form_alter() itself
+ * instead of a form_id-specific form alter so that we're likely to come after
+ * everyone else's alterings, e.g. taxonomy, menu, etc.
+ */
+function twostepnode_form_alter(&$form, $form_state, $form_id) {
+  if ($form_id == 'twostepnode_node_form') {
+    $node = $form['#node'];
+    if (empty($form_state['storage']['title']) && empty($node->title)) {
+      _twostepnode_step1($form, array('title'));
+    }
+    else {
+      // For the actual submit button, add a handler to clear out
+      // $form_state['storage']['title'] so that we actually submit the form.
+      $form['buttons']['submit']['#submit'][] = 'twostepnode_node_form_final_submit';
+    }
+  }
+}
+
+/**
+ * Helper function to convert the node form into step 1 of a multi-step form.
+ *
+ * Marks all form elements to #access FALSE except those required on step 1,
+ * converts the usual "preview" button into a "next" button and hides the
+ * submit button.
+ */
+function _twostepnode_step1(&$form) {
+  // Hide all the elements we don't want on step 1.
+  foreach (element_children($form) as $child) {
+    if ($child != 'buttons' &&
+        (empty($form[$child]['#type']) ||
+         ($form[$child]['#type'] != 'hidden'
+          && $form[$child]['#type'] != 'value'
+          && $form[$child]['#type'] != 'token'
+          && ($child != 'title')))) {
+      $form[$child]['#access'] = FALSE;
+    }
+  }
+
+  // Change preview to next and hide submit.
+  $form['buttons']['preview'] = array(
+    '#type' => 'submit',
+    '#value' => t('Next'),
+    '#weight' => 50,
+    '#submit' => array('twostepnode_node_form_next_handler'),
+  );
+  $form['buttons']['submit']['#access'] = FALSE;
+}
+
+/**
+ * Submit handler for the 'Next' button on step 1.
+ *
+ * Saves the title value into $form_state['storage'].
+ */
+function twostepnode_node_form_next_handler($form, &$form_state) {
+  if (isset($form_state['values']['title'])) {
+    $form_state['storage']['title'] = $form_state['values']['title'];
+  }
+}
+
+/**
+ * Submit handler for the "Save" button on step 2.
+ *
+ * Clears out $form_state['storage']['title'] so the form will submit and will
+ * not rebuild itself.
+ */
+function twostepnode_node_form_final_submit(&$form, &$form_state) {
+  unset($form_state['storage']['title']);
+}
+

