Index: src/wp-admin/js/customize-controls.js
===================================================================
--- src/wp-admin/js/customize-controls.js	(revision 27650)
+++ src/wp-admin/js/customize-controls.js	(working copy)
@@ -853,7 +853,7 @@
 				}
 
 				if ( 'cheatin' === reason )
-					self.cheatin();
+					self.cheatin()
 			});
 		},
 
Index: src/wp-admin/js/customize-widgets.js
===================================================================
--- src/wp-admin/js/customize-widgets.js	(revision 27650)
+++ src/wp-admin/js/customize-widgets.js	(working copy)
@@ -16,7 +16,8 @@
 			save_btn_label: '',
 			save_btn_tooltip: '',
 			remove_btn_label: '',
-			remove_btn_tooltip: ''
+			remove_btn_tooltip: '',
+			error: '',
 		},
 		available_widgets: [], // available widgets for instantiating
 		registered_widgets: [], // all widgets registered
@@ -1172,6 +1173,9 @@
 
 			widget_content = control.container.find( '.widget-content' );
 
+			// Remove a previous error message
+			widget_content.find( '.widget-error' ).remove();
+
 			// @todo Support more selectors than IDs?
 			if ( $.contains( control.container[0], document.activeElement ) && $( document.activeElement ).is( '[id]' ) ) {
 				element_id_to_refocus = $( document.activeElement ).prop( 'id' );
@@ -1219,6 +1223,22 @@
 					has_same_inputs_in_response,
 					is_instance_identical;
 
+				// Check if the user is logged out.
+				if ( '0' === r ) {
+					self.previewer.preview.iframe.hide();
+					self.previewer.login().done( function() {
+						control.updateWidget( args );
+						self.previewer.preview.iframe.show();
+					} );
+					return;
+				}
+
+				// Check for cheaters.
+				if ( '-1' === r ) {
+					self.previewer.cheatin();
+					return;
+				}
+
 				if ( r.success ) {
 					sanitized_form = $( '<div>' + r.data.form + '</div>' );
 
@@ -1274,9 +1294,7 @@
 					 * preview finishing loading.
 					 */
 					is_instance_identical = _( control.setting() ).isEqual( r.data.instance );
-					if ( is_instance_identical ) {
-						control.container.removeClass( 'previewer-loading' );
-					} else {
+					if ( ! is_instance_identical ) {
 						control.is_widget_updating = true; // suppress triggering another updateWidget
 						control.setting( r.data.instance );
 						control.is_widget_updating = false;
@@ -1286,26 +1304,24 @@
 						complete_callback.call( control, null, { no_change: is_instance_identical, ajax_finished: true } );
 					}
 				} else {
-					window.console && window.console.log( r );
-					message = 'FAIL';
+					message = self.i18n.error;
 					if ( r.data && r.data.message ) {
 						message = r.data.message;
 					}
 					if ( complete_callback ) {
 						complete_callback.call( control, message );
 					} else {
-						throw new Error( message );
+						widget_content.prepend( '<p class="widget-error"><strong>' + message + '</strong></p>' );
 					}
 				}
 			} );
 			jqxhr.fail( function ( jqXHR, textStatus ) {
 				if ( complete_callback ) {
 					complete_callback.call( control, textStatus );
-				} else {
-					throw new Error( textStatus );
 				}
 			} );
 			jqxhr.always( function () {
+				control.container.removeClass( 'previewer-loading' );
 				control.container.removeClass( 'widget-form-loading' );
 				inputs.each( function () {
 					$( this ).removeData( 'state' + update_number );
Index: src/wp-includes/class-wp-customize-widgets.php
===================================================================
--- src/wp-includes/class-wp-customize-widgets.php	(revision 27650)
+++ src/wp-includes/class-wp-customize-widgets.php	(working copy)
@@ -424,17 +424,14 @@
 	/**
 	 * Convert a widget setting ID (option path) to its id_base and number components
 	 *
-	 * @throws Widget_Customizer_Exception
-	 * @throws Exception
-	 *
 	 * @param string $setting_id
-	 * @param array
-	 * @return array
+	 * @return WP_Error|array
 	 */
 	static function parse_widget_setting_id( $setting_id ) {
 		if ( ! preg_match( '/^(widget_(.+?))(?:\[(\d+)\])?$/', $setting_id, $matches ) ) {
-			throw new Widget_Customizer_Exception( sprintf( 'Invalid widget setting ID: %s', $setting_id ) );
+			return new WP_Error( 'invalid_setting_id', 'Invalid widget setting ID' );
 		}
+
 		$id_base = $matches[2];
 		$number  = isset( $matches[3] ) ? intval( $matches[3] ) : null;
 		return compact( 'id_base', 'number' );
@@ -500,6 +497,7 @@
 				'save_btn_tooltip' => ( 'Save and preview changes before publishing them.' ),
 				'remove_btn_label' => __( 'Remove' ),
 				'remove_btn_tooltip' => ( 'Trash widget by moving it to the inactive widgets sidebar.' ),
+				'error' => __('An error has occurred. Please reload the page and try again.'),
 			),
 			'tpl' => array(
 				'widget_reorder_nav' => $widget_reorder_nav_tpl,
@@ -912,18 +910,14 @@
 	 * Find and invoke the widget update and control callbacks. Requires that
 	 * $_POST be populated with the instance data.
 	 *
-	 * @throws Widget_Customizer_Exception
-	 * @throws Exception
-	 *
 	 * @param string $widget_id
-	 * @return array
+	 * @return WP_Error|array
 	 */
 	static function call_widget_update( $widget_id ) {
 		global $wp_registered_widget_updates, $wp_registered_widget_controls;
 
 		$options_transaction = new Options_Transaction();
 
-		try {
 			$options_transaction->start();
 			$parsed_id   = self::parse_widget_id( $widget_id );
 			$option_name = 'widget_' . $parsed_id['id_base'];
@@ -936,12 +930,16 @@
 			if ( ! empty( $_POST['sanitized_widget_setting'] ) ) {
 				$sanitized_widget_setting = json_decode( self::get_post_value( 'sanitized_widget_setting' ), true );
 				if ( empty( $sanitized_widget_setting ) ) {
-					throw new Widget_Customizer_Exception( 'Malformed sanitized_widget_setting' );
+				$options_transaction->rollback();
+				return new WP_Error( 'malformed_data', 'Malformed sanitized_widget_setting' );
 				}
+
 				$instance = self::sanitize_widget_instance( $sanitized_widget_setting );
 				if ( is_null( $instance ) ) {
-					throw new Widget_Customizer_Exception( 'Unsanitary sanitized_widget_setting' );
+				$options_transaction->rollback();
+				return new WP_Error( 'unsanitary_data', 'Unsanitary sanitized_widget_setting' );
 				}
+
 				if ( ! is_null( $parsed_id['number'] ) ) {
 					$value = array();
 					$value[$parsed_id['number']] = $instance;
@@ -979,11 +977,14 @@
 			 */
 			if ( 0 !== $options_transaction->count() ) {
 				if ( count( $options_transaction->options ) > 1 ) {
-					throw new Widget_Customizer_Exception( sprintf( 'Widget %1$s unexpectedly updated more than one option.', $widget_id ) );
+				$options_transaction->rollback();
+				return new WP_Error( 'unexpected_update', 'Widget unexpectedly updated more than one option.' );
 				}
+
 				$updated_option_name = key( $options_transaction->options );
 				if ( $updated_option_name !== $option_name ) {
-					throw new Widget_Customizer_Exception( sprintf( 'Widget %1$s updated option "%2$s", but expected "%3$s".', $widget_id, $updated_option_name, $option_name ) );
+				$options_transaction->rollback();
+				return new WP_Error( 'wrong_option', sprintf( 'Widget updated option "%1$s", but expected "%2$s".', $updated_option_name, $option_name ) );
 				}
 			}
 
@@ -1010,11 +1011,6 @@
 			$options_transaction->rollback();
 			return compact( 'instance', 'form' );
 		}
-		catch ( Exception $e ) {
-			$options_transaction->rollback();
-			throw $e;
-		}
-	}
 
 	/**
 	 * Allow customizer to update a widget using its form, but return the new
@@ -1026,17 +1022,19 @@
 	 * @action wp_ajax_update_widget
 	 */
 	static function wp_ajax_update_widget() {
-		$generic_error = __( 'An error has occurred. Please reload the page and try again.' );
 
-		try {
-			if ( ! check_ajax_referer( self::UPDATE_WIDGET_AJAX_ACTION, self::UPDATE_WIDGET_NONCE_POST_KEY, false ) ) {
-				throw new Widget_Customizer_Exception( ( 'Nonce check failed. Reload and try again?' ) );
+		if ( ! is_user_logged_in() ) {
+			wp_die( 0 );
 			}
+
+		check_ajax_referer( self::UPDATE_WIDGET_AJAX_ACTION, self::UPDATE_WIDGET_NONCE_POST_KEY, false );
+
 			if ( ! current_user_can( 'edit_theme_options' ) ) {
-				throw new Widget_Customizer_Exception( ( 'Current user cannot!' ) ); // @todo translate
+			wp_die( -1 );
 			}
-			if ( ! isset( $_POST['widget-id'] ) ) {
-				throw new Widget_Customizer_Exception( ( 'Incomplete request' ) ); // @todo translate
+
+		if ( isset( $_POST['widget-id'] ) ) {
+			wp_send_json_error();
 			}
 
 			unset( $_POST[self::UPDATE_WIDGET_NONCE_POST_KEY], $_POST['action'] );
@@ -1050,29 +1048,21 @@
 			$id_base   = $parsed_id['id_base'];
 
 			if ( isset( $_POST['widget-' . $id_base] ) && is_array( $_POST['widget-' . $id_base] ) && preg_match( '/__i__|%i%/', key( $_POST['widget-' . $id_base] ) ) ) {
-				throw new Widget_Customizer_Exception( 'Cannot pass widget templates to create new instances; apply template vars in JS' );
+			wp_send_json_error();
 			}
 
 			$updated_widget = self::call_widget_update( $widget_id ); // => {instance,form}
+		if ( is_wp_error( $updated_widget ) ) {
+			wp_send_json_error();
+		}
+
 			$form = $updated_widget['form'];
 			$instance = self::sanitize_widget_js_instance( $updated_widget['instance'] );
 
 			wp_send_json_success( compact( 'form', 'instance' ) );
 		}
-		catch( Exception $e ) {
-			if ( $e instanceof Widget_Customizer_Exception ) {
-				$message = $e->getMessage();
-			} else {
-				error_log( sprintf( '%s in %s: %s', get_class( $e ), __FUNCTION__, $e->getMessage() ) );
-				$message = $generic_error;
 			}
-			wp_send_json_error( compact( 'message' ) );
-		}
-	}
-}
 
-class Widget_Customizer_Exception extends Exception {}
-
 class Options_Transaction {
 
 	/**
@@ -1204,10 +1194,7 @@
 			else if ( 'update' === $option_operation['operation'] ) {
 				update_option( $option_operation['option_name'], $option_operation['old_value'] );
 			}
-			else {
-				throw new Exception( 'Unexpected operation' );
 			}
-		}
 		$this->_is_current = false;
 	}
 }
