Index: src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php	(revision 39091)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php	(working copy)
@@ -594,7 +594,6 @@
 			'description'       => __( 'Limit result set to attachments of a particular media type.' ),
 			'type'              => 'string',
 			'enum'              => array_keys( $media_types ),
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$params['mime_type'] = array(
Index: src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php	(revision 39091)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php	(working copy)
@@ -1102,9 +1102,7 @@
 					'type'         => 'string',
 					'format'       => 'ipv4',
 					'context'      => array( 'edit' ),
-					'arg_options'  => array(
-						'default'           => '127.0.0.1',
-					),
+					'default'      => '127.0.0.1',
 				),
 				'author_name'     => array(
 					'description'  => __( 'Display name for the object author.' ),
@@ -1176,17 +1174,13 @@
 					'description'  => __( 'The id for the parent of the object.' ),
 					'type'         => 'integer',
 					'context'      => array( 'view', 'edit', 'embed' ),
-					'arg_options'  => array(
-						'default'           => 0,
-					),
+					'default'      => 0,
 				),
 				'post'             => array(
 					'description'  => __( 'The id of the associated post object.' ),
 					'type'         => 'integer',
 					'context'      => array( 'view', 'edit' ),
-					'arg_options'  => array(
-						'default'           => 0,
-					),
+					'default'      => 0,
 				),
 				'status'           => array(
 					'description'  => __( 'State of the object.' ),
@@ -1252,26 +1246,28 @@
 			'description'       => __( 'Limit response to resources published after a given ISO8601 compliant date.' ),
 			'type'              => 'string',
 			'format'            => 'date-time',
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$query_params['author'] = array(
 			'description'       => __( 'Limit result set to comments assigned to specific user ids. Requires authorization.' ),
-			'sanitize_callback' => 'wp_parse_id_list',
 			'type'              => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 		);
 
 		$query_params['author_exclude'] = array(
 			'description'       => __( 'Ensure result set excludes comments assigned to specific user ids. Requires authorization.' ),
-			'sanitize_callback' => 'wp_parse_id_list',
 			'type'              => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 		);
 
 		$query_params['author_email'] = array(
 			'default'           => null,
 			'description'       => __( 'Limit result set to that from a specific author email. Requires authorization.' ),
 			'format'            => 'email',
-			'sanitize_callback' => 'sanitize_email',
 			'type'              => 'string',
 		);
 
@@ -1279,43 +1275,40 @@
 			'description'       => __( 'Limit response to resources published before a given ISO8601 compliant date.' ),
 			'type'              => 'string',
 			'format'            => 'date-time',
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$query_params['exclude'] = array(
 			'description'        => __( 'Ensure result set excludes specific ids.' ),
 			'type'               => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 			'default'            => array(),
-			'sanitize_callback'  => 'wp_parse_id_list',
 		);
 
 		$query_params['include'] = array(
 			'description'        => __( 'Limit result set to specific ids.' ),
 			'type'               => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 			'default'            => array(),
-			'sanitize_callback'  => 'wp_parse_id_list',
 		);
 
 		$query_params['karma'] = array(
 			'default'           => null,
 			'description'       => __( 'Limit result set to that of a particular comment karma. Requires authorization.' ),
-			'sanitize_callback' => 'absint',
 			'type'              => 'integer',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$query_params['offset'] = array(
 			'description'        => __( 'Offset the result set by a specific number of comments.' ),
 			'type'               => 'integer',
-			'sanitize_callback'  => 'absint',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$query_params['order']      = array(
 			'description'           => __( 'Order sort attribute ascending or descending.' ),
 			'type'                  => 'string',
-			'sanitize_callback'     => 'sanitize_key',
-			'validate_callback'     => 'rest_validate_request_arg',
 			'default'               => 'desc',
 			'enum'                  => array(
 				'asc',
@@ -1326,8 +1319,6 @@
 		$query_params['orderby']    = array(
 			'description'           => __( 'Sort collection by object attribute.' ),
 			'type'                  => 'string',
-			'sanitize_callback'     => 'sanitize_key',
-			'validate_callback'     => 'rest_validate_request_arg',
 			'default'               => 'date_gmt',
 			'enum'                  => array(
 				'date',
@@ -1343,22 +1334,28 @@
 		$query_params['parent'] = array(
 			'default'           => array(),
 			'description'       => __( 'Limit result set to resources of specific parent ids.' ),
-			'sanitize_callback' => 'wp_parse_id_list',
 			'type'              => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 		);
 
 		$query_params['parent_exclude'] = array(
 			'default'           => array(),
 			'description'       => __( 'Ensure result set excludes specific parent ids.' ),
-			'sanitize_callback' => 'wp_parse_id_list',
 			'type'              => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 		);
 
 		$query_params['post']   = array(
 			'default'           => array(),
 			'description'       => __( 'Limit result set to resources assigned to specific post ids.' ),
 			'type'              => 'array',
-			'sanitize_callback' => 'wp_parse_id_list',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 		);
 
 		$query_params['status'] = array(
Index: src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php	(revision 39091)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php	(working copy)
@@ -1974,20 +1974,6 @@
 				'items'       => array(
 					'type'    => 'integer',
 				),
-				'arg_options' => array(
-					'sanitize_callback' => 'wp_parse_id_list',
-				),
-				'context'     => array( 'view', 'edit' ),
-			);
-			$schema['properties'][ $base . '_exclude' ] = array(
-				'description' => sprintf( __( 'The terms in the %s taxonomy that should not be assigned to the object.' ), $taxonomy->name ),
-				'type'        => 'array',
-				'items'       => array(
-					'type'    => 'integer',
-				),
-				'arg_options' => array(
-					'sanitize_callback' => 'wp_parse_id_list',
-				),
 				'context'     => array( 'view', 'edit' ),
 			);
 		}
@@ -2012,21 +1998,24 @@
 			'description'        => __( 'Limit response to resources published after a given ISO8601 compliant date.' ),
 			'type'               => 'string',
 			'format'             => 'date-time',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		if ( post_type_supports( $this->post_type, 'author' ) ) {
 			$params['author'] = array(
 				'description'         => __( 'Limit result set to posts assigned to specific authors.' ),
 				'type'                => 'array',
+				'items'               => array(
+					'type'            => 'integer',
+				),
 				'default'             => array(),
-				'sanitize_callback'   => 'wp_parse_id_list',
 			);
 			$params['author_exclude'] = array(
 				'description'         => __( 'Ensure result set excludes posts assigned to specific authors.' ),
 				'type'                => 'array',
+				'items'               => array(
+					'type'            => 'integer',
+				),
 				'default'             => array(),
-				'sanitize_callback'   => 'wp_parse_id_list',
 			);
 		}
 
@@ -2034,37 +2023,36 @@
 			'description'        => __( 'Limit response to resources published before a given ISO8601 compliant date.' ),
 			'type'               => 'string',
 			'format'             => 'date-time',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$params['exclude'] = array(
 			'description'        => __( 'Ensure result set excludes specific ids.' ),
 			'type'               => 'array',
+			'items'              => array(
+				'type'           => 'integer',
+			),
 			'default'            => array(),
-			'sanitize_callback'  => 'wp_parse_id_list',
 		);
 
 		$params['include'] = array(
 			'description'        => __( 'Limit result set to specific ids.' ),
 			'type'               => 'array',
+			'items'              => array(
+				'type'           => 'integer',
+			),
 			'default'            => array(),
-			'sanitize_callback'  => 'wp_parse_id_list',
 		);
 
 		if ( 'page' === $this->post_type || post_type_supports( $this->post_type, 'page-attributes' ) ) {
 			$params['menu_order'] = array(
 				'description'        => __( 'Limit result set to resources with a specific menu_order value.' ),
 				'type'               => 'integer',
-				'sanitize_callback'  => 'absint',
-				'validate_callback'  => 'rest_validate_request_arg',
 			);
 		}
 
 		$params['offset'] = array(
 			'description'        => __( 'Offset the result set by a specific number of items.' ),
 			'type'               => 'integer',
-			'sanitize_callback'  => 'absint',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$params['order'] = array(
@@ -2072,7 +2060,6 @@
 			'type'               => 'string',
 			'default'            => 'desc',
 			'enum'               => array( 'asc', 'desc' ),
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$params['orderby'] = array(
@@ -2087,7 +2074,6 @@
 				'title',
 				'slug',
 			),
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		if ( 'page' === $this->post_type || post_type_supports( $this->post_type, 'page-attributes' ) ) {
@@ -2100,13 +2086,17 @@
 			$params['parent'] = array(
 				'description'       => __( 'Limit result set to those of particular parent ids.' ),
 				'type'              => 'array',
-				'sanitize_callback' => 'wp_parse_id_list',
+				'items'             => array(
+					'type'          => 'integer',
+				),
 				'default'           => array(),
 			);
 			$params['parent_exclude'] = array(
 				'description'       => __( 'Limit result set to all items except those of a particular parent id.' ),
 				'type'              => 'array',
-				'sanitize_callback' => 'wp_parse_id_list',
+				'items'             => array(
+					'type'          => 'integer',
+				),
 				'default'           => array(),
 			);
 		}
@@ -2114,7 +2104,6 @@
 		$params['slug'] = array(
 			'description'       => __( 'Limit result set to posts with a specific slug.' ),
 			'type'              => 'string',
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$params['status'] = array(
@@ -2134,7 +2123,18 @@
 			$params[ $base ] = array(
 				'description'       => sprintf( __( 'Limit result set to all items that have the specified term assigned in the %s taxonomy.' ), $base ),
 				'type'              => 'array',
-				'sanitize_callback' => 'wp_parse_id_list',
+				'items'             => array(
+					'type'          => 'integer',
+				),
+				'default'           => array(),
+			);
+
+			$params[ $base . '_exclude' ] = array(
+				'description' => sprintf( __( 'Limit result set to all items except those that have the specified term assigned in the %s taxonomy.' ), $base ),
+				'type'        => 'array',
+				'items'       => array(
+					'type'    => 'integer',
+				),
 				'default'           => array(),
 			);
 		}
@@ -2143,7 +2143,6 @@
 			$params['sticky'] = array(
 				'description'       => __( 'Limit result set to items that are sticky.' ),
 				'type'              => 'boolean',
-				'sanitize_callback' => 'rest_parse_request_arg',
 			);
 		}
 
Index: src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php	(revision 39091)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php	(working copy)
@@ -301,7 +301,6 @@
 		$new_params['type'] = array(
 			'description'  => __( 'Limit results to resources associated with a specific post type.' ),
 			'type'         => 'string',
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 		return $new_params;
 	}
Index: src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php	(revision 39091)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php	(working copy)
@@ -887,42 +887,41 @@
 		$query_params['exclude'] = array(
 			'description'       => __( 'Ensure result set excludes specific ids.' ),
 			'type'              => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 			'default'           => array(),
-			'sanitize_callback' => 'wp_parse_id_list',
 		);
 
 		$query_params['include'] = array(
 			'description'       => __( 'Limit result set to specific ids.' ),
 			'type'              => 'array',
+			'items'             => array(
+				'type'          => 'integer',
+			),
 			'default'           => array(),
-			'sanitize_callback' => 'wp_parse_id_list',
 		);
 
 		if ( ! $taxonomy->hierarchical ) {
 			$query_params['offset'] = array(
 				'description'       => __( 'Offset the result set by a specific number of items.' ),
 				'type'              => 'integer',
-				'sanitize_callback' => 'absint',
-				'validate_callback' => 'rest_validate_request_arg',
 			);
 		}
 
 		$query_params['order'] = array(
 			'description'       => __( 'Order sort attribute ascending or descending.' ),
 			'type'              => 'string',
-			'sanitize_callback' => 'sanitize_key',
 			'default'           => 'asc',
 			'enum'              => array(
 				'asc',
 				'desc',
 			),
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$query_params['orderby'] = array(
 			'description'       => __( 'Sort collection by resource attribute.' ),
 			'type'              => 'string',
-			'sanitize_callback' => 'sanitize_key',
 			'default'           => 'name',
 			'enum'              => array(
 				'id',
@@ -933,23 +932,18 @@
 				'description',
 				'count',
 			),
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$query_params['hide_empty'] = array(
 			'description'       => __( 'Whether to hide resources not assigned to any posts.' ),
 			'type'              => 'boolean',
 			'default'           => false,
-			'sanitize_callback' => 'rest_sanitize_request_arg',
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		if ( $taxonomy->hierarchical ) {
 			$query_params['parent'] = array(
 				'description'       => __( 'Limit result set to resources assigned to a specific parent.' ),
 				'type'              => 'integer',
-				'sanitize_callback' => 'absint',
-				'validate_callback' => 'rest_validate_request_arg',
 			);
 		}
 
@@ -957,13 +951,11 @@
 			'description'       => __( 'Limit result set to resources assigned to a specific post.' ),
 			'type'              => 'integer',
 			'default'           => null,
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		$query_params['slug'] = array(
 			'description'       => __( 'Limit result set to resources with a specific slug.' ),
 			'type'              => 'string',
-			'validate_callback' => 'rest_validate_request_arg',
 		);
 
 		return $query_params;
Index: src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php	(revision 39091)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php	(working copy)
@@ -1022,9 +1022,6 @@
 						'type'    => 'string',
 					),
 					'context'     => array( 'edit' ),
-					'arg_options' => array(
-						'sanitize_callback' => 'wp_parse_slug_list',
-					),
 				),
 				'password'        => array(
 					'description' => __( 'Password for the resource (never included).' ),
@@ -1091,31 +1088,31 @@
 		$query_params['exclude'] = array(
 			'description'        => __( 'Ensure result set excludes specific ids.' ),
 			'type'               => 'array',
+			'items'              => array(
+				'type'           => 'integer',
+			),
 			'default'            => array(),
-			'sanitize_callback'  => 'wp_parse_id_list',
 		);
 
 		$query_params['include'] = array(
 			'description'        => __( 'Limit result set to specific ids.' ),
 			'type'               => 'array',
+			'items'              => array(
+				'type'           => 'integer',
+			),
 			'default'            => array(),
-			'sanitize_callback'  => 'wp_parse_id_list',
 		);
 
 		$query_params['offset'] = array(
 			'description'        => __( 'Offset the result set by a specific number of items.' ),
 			'type'               => 'integer',
-			'sanitize_callback'  => 'absint',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$query_params['order'] = array(
 			'default'            => 'asc',
 			'description'        => __( 'Order sort attribute ascending or descending.' ),
 			'enum'               => array( 'asc', 'desc' ),
-			'sanitize_callback'  => 'sanitize_key',
 			'type'               => 'string',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$query_params['orderby'] = array(
@@ -1130,21 +1127,20 @@
 				'email',
 				'url',
 			),
-			'sanitize_callback'  => 'sanitize_key',
 			'type'               => 'string',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$query_params['slug']    = array(
 			'description'        => __( 'Limit result set to resources with a specific slug.' ),
 			'type'               => 'string',
-			'validate_callback'  => 'rest_validate_request_arg',
 		);
 
 		$query_params['roles']   = array(
 			'description'        => __( 'Limit result set to resources matching at least one specific role provided. Accepts csv list or single role.' ),
 			'type'               => 'array',
-			'sanitize_callback'  => 'wp_parse_slug_list',
+			'items'              => array(
+				'type'           => 'string',
+			),
 		);
 
 		return $query_params;
Index: tests/phpunit/tests/rest-api/rest-categories-controller.php
===================================================================
--- tests/phpunit/tests/rest-api/rest-categories-controller.php	(revision 39091)
+++ tests/phpunit/tests/rest-api/rest-categories-controller.php	(working copy)
@@ -428,6 +428,15 @@
 		$this->assertEquals( 'Child', $data[0]['name'] );
 	}
 
+	public function test_get_terms_invalid_parent_arg() {
+		$category1 = $this->factory->category->create( array( 'name' => 'Parent' ) );
+		$this->factory->category->create( array( 'name' => 'Child', 'parent' => $category1 ) );
+		$request = new WP_REST_Request( 'GET', '/wp/v2/categories' );
+		$request->set_param( 'parent', 'invalid-parent' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
 	public function test_get_terms_private_taxonomy() {
 		register_taxonomy( 'robin', 'post', array( 'public' => false ) );
 		$this->factory->term->create( array( 'name' => 'Cape', 'taxonomy' => 'robin' ) );
Index: tests/phpunit/tests/rest-api/rest-comments-controller.php
===================================================================
--- tests/phpunit/tests/rest-api/rest-comments-controller.php	(revision 39091)
+++ tests/phpunit/tests/rest-api/rest-comments-controller.php	(working copy)
@@ -32,12 +32,12 @@
 			'role' => 'subscriber',
 		) );
 		self::$author_id = $factory->user->create( array(
-			'role'         => 'author',
+			'role'		 => 'author',
 			'display_name' => 'Sea Captain',
 			'first_name'   => 'Horatio',
-			'last_name'    => 'McCallister',
+			'last_name'	=> 'McCallister',
 			'user_email'   => 'captain@thefryingdutchman.com',
-			'user_url'     => 'http://thefryingdutchman.com',
+			'user_url'	 => 'http://thefryingdutchman.com',
 		) );
 
 		self::$post_id = $factory->post->create();
@@ -54,12 +54,12 @@
 		self::$approved_id = $factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => 0,
+			'user_id'		  => 0,
 		) );
 		self::$hold_id = $factory->comment->create( array(
 			'comment_approved' => 0,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 	}
 
@@ -300,6 +300,15 @@
 		$data = $response->get_data();
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( $id3, $data[0]['id'] );
+		// Orderby=>invalid should fail
+		$request->set_param( 'orderby', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+		// fails on invalid id
+		$request->set_param( 'orderby', array( 'include' ) );
+		$request->set_param( 'include', array( 'invalid' ) );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_exclude_query() {
@@ -320,6 +329,11 @@
 		$data = $response->get_data();
 		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
 		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
+
+		// fails on invalid id
+		$request->set_param( 'exclude', array( 'invalid' ) );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_offset_query() {
@@ -343,6 +357,10 @@
 		$request->set_param( 'page', 3 );
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 2, $response->get_data() );
+		// 'offset' with invalid value errors
+		$request->set_param( 'offset', 'moreplease' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_order_query() {
@@ -364,6 +382,10 @@
 		$response = $this->server->dispatch( $request );
 		$data = $response->get_data();
 		$this->assertEquals( self::$approved_id, $data[0]['id'] );
+		// order=>asc,id should fail
+		$request->set_param( 'order', 'asc,id' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_private_post_no_permissions() {
@@ -381,7 +403,7 @@
 		$args = array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$author_id,
+			'user_id'		  => self::$author_id,
 		);
 		$this->factory->comment->create( $args );
 		$args['user_id'] = self::$subscriber_id;
@@ -402,8 +424,13 @@
 		$this->assertEquals( 200, $response->get_status() );
 		$comments = $response->get_data();
 		$this->assertCount( 2, $comments );
+		// Invalid author param errors
+		$request->set_param( 'author', 'skippy' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 		// Unavailable to unauthenticated; defaults to error
 		wp_set_current_user( 0 );
+		$request->set_param( 'author', array( self::$author_id, self::$subscriber_id ) );
 		$response = $this->server->dispatch( $request );
 		$this->assertErrorResponse( 'rest_forbidden_param', $response, 401 );
 	}
@@ -414,7 +441,7 @@
 		$args = array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$author_id,
+			'user_id'		  => self::$author_id,
 		);
 		$this->factory->comment->create( $args );
 		$args['user_id'] = self::$subscriber_id;
@@ -441,8 +468,14 @@
 		$this->assertEquals( 200, $response->get_status() );
 		$comments = $response->get_data();
 		$this->assertCount( 2, $comments );
+		// 'author_exclude' for both invalid author
+		$request = new WP_REST_Request( 'GET', '/wp/v2/comments' );
+		$request->set_param( 'author_exclude', 'skippy' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 		// Unavailable to unauthenticated; defaults to error
 		wp_set_current_user( 0 );
+		$request->set_param( 'author_exclude', array( self::$author_id, self::$subscriber_id ) );
 		$response = $this->server->dispatch( $request );
 		$this->assertErrorResponse( 'rest_forbidden_param', $response, 401 );
 	}
@@ -470,6 +503,10 @@
 		$request->set_param( 'parent', array( $parent_id, $parent_id2 ) );
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 2, $response->get_data() );
+		// Invalid parent should error
+		$request->set_param( 'parent', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_parent_exclude_arg() {
@@ -495,6 +532,10 @@
 		$request->set_param( 'parent_exclude', array( $parent_id, $parent_id2 ) );
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 3, $response->get_data() );
+		// Invalid parent id should error
+		$request->set_param( 'parent_exclude', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_search_query() {
@@ -537,7 +578,7 @@
 		$this->assertEquals( 50, $headers['X-WP-Total'] );
 		$this->assertEquals( 5, $headers['X-WP-TotalPages'] );
 		$next_link = add_query_arg( array(
-			'page'    => 2,
+			'page'	=> 2,
 			), rest_url( '/wp/v2/comments' ) );
 		$this->assertFalse( stripos( $headers['Link'], 'rel="prev"' ) );
 		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
@@ -553,11 +594,11 @@
 		$this->assertEquals( 51, $headers['X-WP-Total'] );
 		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
 		$prev_link = add_query_arg( array(
-			'page'    => 2,
+			'page'	=> 2,
 			), rest_url( '/wp/v2/comments' ) );
 		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
 		$next_link = add_query_arg( array(
-			'page'    => 4,
+			'page'	=> 4,
 			), rest_url( '/wp/v2/comments' ) );
 		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
 		// Last page
@@ -568,7 +609,7 @@
 		$this->assertEquals( 51, $headers['X-WP-Total'] );
 		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
 		$prev_link = add_query_arg( array(
-			'page'    => 5,
+			'page'	=> 5,
 			), rest_url( '/wp/v2/comments' ) );
 		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
 		$this->assertFalse( stripos( $headers['Link'], 'rel="next"' ) );
@@ -580,7 +621,7 @@
 		$this->assertEquals( 51, $headers['X-WP-Total'] );
 		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
 		$prev_link = add_query_arg( array(
-			'page'    => 6,
+			'page'	=> 6,
 			), rest_url( '/wp/v2/comments' ) );
 		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
 		$this->assertFalse( stripos( $headers['Link'], 'rel="next"' ) );
@@ -596,15 +637,15 @@
 
 	public function test_get_comments_valid_date() {
 		$comment1 = $this->factory->comment->create( array(
-			'comment_date'    => '2016-01-15T00:00:00Z',
+			'comment_date'	=> '2016-01-15T00:00:00Z',
 			'comment_post_ID' => self::$post_id,
 		) );
 		$comment2 = $this->factory->comment->create( array(
-			'comment_date'    => '2016-01-16T00:00:00Z',
+			'comment_date'	=> '2016-01-16T00:00:00Z',
 			'comment_post_ID' => self::$post_id,
 		) );
 		$comment3 = $this->factory->comment->create( array(
-			'comment_date'    => '2016-01-17T00:00:00Z',
+			'comment_date'	=> '2016-01-17T00:00:00Z',
 			'comment_post_ID' => self::$post_id,
 		) );
 
@@ -720,14 +761,14 @@
 		$comment_id_1 = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		$child_comment = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_parent'   => $comment_id_1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%s', $comment_id_1 ) );
@@ -740,7 +781,7 @@
 		$comment_id_1 = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%s', $comment_id_1 ) );
@@ -753,12 +794,12 @@
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
 			'content' => 'Worst Comment Ever!',
-			'date'    => '2014-11-07T10:14:25',
+			'date'	=> '2014-11-07T10:14:25',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -779,11 +820,11 @@
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_name'  => 'Reverend Lovejoy',
 			'author_email' => 'lovejoy@example.com',
 			'author_url'   => 'http://timothylovejoy.jr',
-			'content'      => array(
+			'content'	  => array(
 				'raw' => 'Once something has been approved by the government, it\'s no longer immoral.',
 			),
 		);
@@ -804,7 +845,7 @@
 		update_option( 'require_name_email', 1 );
 
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'content' => 'Now, I don\'t want you to worry class. These tests will have no affect on your grades. They merely determine your future social status and financial success. If any.',
 		);
 
@@ -822,9 +863,9 @@
 		update_option( 'require_name_email', 1 );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_email' => 'ekrabappel@springfield-elementary.edu',
-			'content'      => 'Now, I don\'t want you to worry class. These tests will have no affect on your grades. They merely determine your future social status and financial success. If any.',
+			'content'	  => 'Now, I don\'t want you to worry class. These tests will have no affect on your grades. They merely determine your future social status and financial success. If any.',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -841,9 +882,9 @@
 		update_option( 'require_name_email', 1 );
 
 		$params = array(
-			'post'        => self::$post_id,
+			'post'		=> self::$post_id,
 			'author_name' => 'Edna Krabappel',
-			'content'     => 'Now, I don\'t want you to worry class. These tests will have no affect on your grades. They merely determine your future social status and financial success. If any.',
+			'content'	 => 'Now, I don\'t want you to worry class. These tests will have no affect on your grades. They merely determine your future social status and financial success. If any.',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -860,11 +901,11 @@
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_name'  => 'Reverend Lovejoy',
 			'author_email' => 'lovejoy@example.com',
 			'author_url'   => 'http://timothylovejoy.jr',
-			'content'      => '',
+			'content'	  => '',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -879,12 +920,12 @@
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_name'  => 'Reverend Lovejoy',
 			'author_email' => 'lovejoy@example.com',
 			'author_url'   => 'http://timothylovejoy.jr',
-			'content'      => 'It\'s all over\, people! We don\'t have a prayer!',
-			'date'         => rand_str(),
+			'content'	  => 'It\'s all over\, people! We don\'t have a prayer!',
+			'date'		 => rand_str(),
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -904,13 +945,13 @@
 
 		wp_set_current_user( self::$admin_id );
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
 			'author' => $subscriber_id,
 			'content' => 'Worst Comment Ever!',
-			'date'    => '2014-11-07T10:14:25',
+			'date'	=> '2014-11-07T10:14:25',
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -928,13 +969,13 @@
 		wp_set_current_user( self::$admin_id );
 
 		$params = array(
-			'post'    => $post_id,
-			'author'       => self::$admin_id,
+			'post'	=> $post_id,
+			'author'	   => self::$admin_id,
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
 			'content' => 'Worst Comment Ever!',
-			'date'    => '2014-11-07T10:14:25',
+			'date'	=> '2014-11-07T10:14:25',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -957,6 +998,28 @@
 		$this->assertEquals( $comment_id, $collection_data[0]['id'] );
 	}
 
+	public function test_create_comment_invalid_email() {
+		$post_id = $this->factory->post->create();
+		wp_set_current_user( self::$admin_id );
+
+		$params = array(
+			'post'	=> $post_id,
+			'author'	   => self::$admin_id,
+			'author_name'  => 'Comic Book Guy',
+			'author_email' => 'hello:)',
+			'author_url'   => 'http://androidsdungeon.com',
+			'content' => 'Worst Comment Ever!',
+			'date'	=> '2014-11-07T10:14:25',
+		);
+
+		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
+		$request->add_header( 'content-type', 'application/json' );
+		$request->set_body( wp_json_encode( $params ) );
+
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
 	public function test_create_item_current_user() {
 		$user_id = $this->factory->user->create( array(
 			'role' => 'subscriber',
@@ -995,12 +1058,12 @@
 		wp_set_current_user( self::$admin_id );
 
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'author_name'  => 'Homer Jay Simpson',
 			'author_email' => 'chunkylover53@aol.com',
 			'author_url'   => 'http://compuglobalhypermeganet.com',
 			'content' => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
-			'author'    => self::$subscriber_id,
+			'author'	=> self::$subscriber_id,
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1020,12 +1083,12 @@
 		wp_set_current_user( self::$subscriber_id );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_name'  => 'Homer Jay Simpson',
 			'author_email' => 'chunkylover53@aol.com',
 			'author_url'   => 'http://compuglobalhypermeganet.com',
-			'content'      => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
-			'author'       => self::$admin_id,
+			'content'	  => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
+			'author'	   => self::$admin_id,
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1040,13 +1103,13 @@
 		wp_set_current_user( self::$subscriber_id );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_name'  => 'Homer Jay Simpson',
 			'author_email' => 'chunkylover53@aol.com',
 			'author_url'   => 'http://compuglobalhypermeganet.com',
-			'content'      => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
-			'author'       => self::$subscriber_id,
-			'karma'        => 100,
+			'content'	  => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
+			'author'	   => self::$subscriber_id,
+			'karma'		=> 100,
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1057,17 +1120,58 @@
 		$this->assertErrorResponse( 'rest_comment_invalid_karma', $response, 403 );
 	}
 
+	public function test_create_comment_invalid_post() {
+		wp_set_current_user( self::$subscriber_id );
+
+		$params = array(
+			'post'		   => 'some-slug',
+			'author_name'  => 'Homer Jay Simpson',
+			'author_email' => 'chunkylover53@aol.com',
+			'author_url'   => 'http://compuglobalhypermeganet.com',
+			'content'	   => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
+			'author'	   => self::$subscriber_id,
+		);
+
+		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
+		$request->add_header( 'content-type', 'application/json' );
+		$request->set_body( wp_json_encode( $params ) );
+		$response = $this->server->dispatch( $request );
+
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
+	public function test_create_comment_karma_invalid_value() {
+		wp_set_current_user( self::$subscriber_id );
+
+		$params = array(
+			'post'		 => self::$post_id,
+			'author_name'  => 'Homer Jay Simpson',
+			'author_email' => 'chunkylover53@aol.com',
+			'author_url'   => 'http://compuglobalhypermeganet.com',
+			'content'	  => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
+			'author'	   => self::$subscriber_id,
+			'karma'		=> 'themostkarmaever',
+		);
+
+		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
+		$request->add_header( 'content-type', 'application/json' );
+		$request->set_body( wp_json_encode( $params ) );
+		$response = $this->server->dispatch( $request );
+
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
 	public function test_create_comment_status_without_permission() {
 		wp_set_current_user( self::$subscriber_id );
 
 		$params = array(
-			'post'         => self::$post_id,
+			'post'		 => self::$post_id,
 			'author_name'  => 'Homer Jay Simpson',
 			'author_email' => 'chunkylover53@aol.com',
 			'author_url'   => 'http://compuglobalhypermeganet.com',
-			'content'      => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
-			'author'       => self::$subscriber_id,
-			'status'        => 'approved',
+			'content'	  => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
+			'author'	   => self::$subscriber_id,
+			'status'		=> 'approved',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1083,14 +1187,14 @@
 		wp_set_current_user( self::$admin_id );
 
 		$params = array(
-			'post'         => $post_id,
+			'post'		 => $post_id,
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
-			'author_ip'    => '139.130.4.5',
+			'author_ip'	=> '139.130.4.5',
 			'author_url'   => 'http://androidsdungeon.com',
 			'author_user_agent' => 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
-			'content'      => 'Worst Comment Ever!',
-			'status'       => 'approved',
+			'content'	  => 'Worst Comment Ever!',
+			'status'	   => 'approved',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1113,9 +1217,9 @@
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
-			'author_ip'    => '867.5309',
-			'content'      => 'Worst Comment Ever!',
-			'status'       => 'approved',
+			'author_ip'	=> '867.5309',
+			'content'	  => 'Worst Comment Ever!',
+			'status'	   => 'approved',
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1133,8 +1237,8 @@
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
-			'content'      => 'Worst Comment Ever!',
-			'status'       => 'approved',
+			'content'	  => 'Worst Comment Ever!',
+			'status'	   => 'approved',
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1151,8 +1255,8 @@
 			'author_name'  => 'Homer Jay Simpson',
 			'author_email' => 'chunkylover53@aol.com',
 			'author_url'   => 'http://compuglobalhypermeganet.com',
-			'content'      => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
-			'author'       => self::$subscriber_id,
+			'content'	  => 'Here\’s to alcohol: the cause of, and solution to, all of life\’s problems.',
+			'author'	   => self::$subscriber_id,
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1167,12 +1271,12 @@
 		wp_set_current_user( self::$subscriber_id );
 
 		$params = array(
-			'post'         => self::$draft_id,
+			'post'		 => self::$draft_id,
 			'author_name'  => 'Ishmael',
 			'author_email' => 'herman-melville@earthlink.net',
 			'author_url'   => 'https://en.wikipedia.org/wiki/Herman_Melville',
-			'content'      => 'Call me Ishmael.',
-			'author'       => self::$subscriber_id,
+			'content'	  => 'Call me Ishmael.',
+			'author'	   => self::$subscriber_id,
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1187,12 +1291,12 @@
 		wp_set_current_user( self::$subscriber_id );
 
 		$params = array(
-			'post'         => self::$trash_id,
+			'post'		 => self::$trash_id,
 			'author_name'  => 'Ishmael',
 			'author_email' => 'herman-melville@earthlink.net',
 			'author_url'   => 'https://en.wikipedia.org/wiki/Herman_Melville',
-			'content'      => 'Call me Ishmael.',
-			'author'       => self::$subscriber_id,
+			'content'	  => 'Call me Ishmael.',
+			'author'	   => self::$subscriber_id,
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1207,12 +1311,12 @@
 		wp_set_current_user( self::$subscriber_id );
 
 		$params = array(
-			'post'         => self::$private_id,
+			'post'		 => self::$private_id,
 			'author_name'  => 'Homer Jay Simpson',
 			'author_email' => 'chunkylover53@aol.com',
 			'author_url'   => 'http://compuglobalhypermeganet.com',
-			'content'      => 'I\’d be a vegetarian if bacon grew on trees.',
-			'author'       => self::$subscriber_id,
+			'content'	  => 'I\’d be a vegetarian if bacon grew on trees.',
+			'author'	   => self::$subscriber_id,
 		);
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1226,16 +1330,16 @@
 	public function test_create_item_duplicate() {
 		$this->factory->comment->create(
 			array(
-				'comment_post_ID'      => self::$post_id,
-				'comment_author'       => 'Guy N. Cognito',
+				'comment_post_ID'	  => self::$post_id,
+				'comment_author'	   => 'Guy N. Cognito',
 				'comment_author_email' => 'chunkylover53@aol.co.uk',
-				'comment_content'      => 'Homer? Who is Homer? My name is Guy N. Cognito.',
+				'comment_content'	  => 'Homer? Who is Homer? My name is Guy N. Cognito.',
 			)
 		);
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'author_name'  => 'Guy N. Cognito',
 			'author_email' => 'chunkylover53@aol.co.uk',
 			'content' => 'Homer? Who is Homer? My name is Guy N. Cognito.',
@@ -1256,7 +1360,7 @@
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'      => $post_id,
+			'post'	  => $post_id,
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1282,9 +1386,9 @@
 		wp_set_current_user( self::$admin_id );
 
 		$params = array(
-			'post'         => self::$post_id,
-			'author'       => REST_TESTS_IMPOSSIBLY_HIGH_NUMBER,
-			'content'      => 'It\'s all over\, people! We don\'t have a prayer!',
+			'post'		 => self::$post_id,
+			'author'	   => REST_TESTS_IMPOSSIBLY_HIGH_NUMBER,
+			'content'	  => 'It\'s all over\, people! We don\'t have a prayer!',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1300,9 +1404,9 @@
 
 		$author = new WP_User( self::$author_id );
 		$params = array(
-			'post'         => self::$post_id,
-			'author'       => self::$author_id,
-			'content'      => 'It\'s all over\, people! We don\'t have a prayer!',
+			'post'		 => self::$post_id,
+			'author'	   => self::$author_id,
+			'content'	  => 'It\'s all over\, people! We don\'t have a prayer!',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1322,7 +1426,7 @@
 		wp_set_current_user( 0 );
 
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
@@ -1337,11 +1441,11 @@
 		$this->assertEquals( 201, $response->get_status() );
 
 		$params = array(
-			'post'    => self::$post_id,
+			'post'	=> self::$post_id,
 			'author_name'  => 'Comic Book Guy',
 			'author_email' => 'cbg@androidsdungeon.com',
 			'author_url'   => 'http://androidsdungeon.com',
-			'content'      => 'Shakes fist at sky',
+			'content'	  => 'Shakes fist at sky',
 		);
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
@@ -1358,15 +1462,15 @@
 		wp_set_current_user( self::$admin_id );
 
 		$params = array(
-			'author'       => self::$subscriber_id,
+			'author'	   => self::$subscriber_id,
 			'author_name'  => 'Disco Stu',
 			'author_url'   => 'http://stusdisco.com',
 			'author_email' => 'stu@stusdisco.com',
-			'author_ip'    => '4.4.4.4',
-			'content'      => 'Testing.',
-			'date'         => '2014-11-07T10:14:25',
-			'karma'        => 100,
-			'post'         => $post_id,
+			'author_ip'	=> '4.4.4.4',
+			'content'	  => 'Testing.',
+			'date'		 => '2014-11-07T10:14:25',
+			'karma'		=> 100,
+			'post'		 => $post_id,
 		);
 		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d', self::$approved_id ) );
 		$request->add_header( 'content-type', 'application/json' );
@@ -1500,7 +1604,7 @@
 
 		$params = array(
 			'content' => rand_str(),
-			'date'    => rand_str(),
+			'date'	=> rand_str(),
 		);
 
 		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d', self::$approved_id ) );
@@ -1559,7 +1663,7 @@
 		$private_comment_id = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$private_id,
-			'user_id'          => 0,
+			'user_id'		  => 0,
 		));
 
 		wp_set_current_user( self::$subscriber_id );
@@ -1580,13 +1684,13 @@
 		$comment_id_1 = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		$child_comment = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		// Check if comment 1 does not have the child link.
@@ -1615,7 +1719,7 @@
 		$comment_id = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		));
 		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d', $comment_id ) );
 
@@ -1631,7 +1735,7 @@
 		$comment_id = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		));
 		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d', $comment_id ) );
 		$request['force'] = true;
@@ -1648,7 +1752,7 @@
 		$comment_id = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		));
 		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d', $comment_id ) );
 		$response = $this->server->dispatch( $request );
@@ -1681,14 +1785,14 @@
 		$comment_id_1 = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		$child_comment = $this->factory->comment->create( array(
 			'comment_approved' => 1,
 			'comment_parent'   => $comment_id_1,
 			'comment_post_ID'  => self::$post_id,
-			'user_id'          => self::$subscriber_id,
+			'user_id'		  => self::$subscriber_id,
 		) );
 
 		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%s', $child_comment ) );
@@ -1726,6 +1830,10 @@
 		$this->assertArrayHasKey( 'post', $properties );
 		$this->assertArrayHasKey( 'status', $properties );
 		$this->assertArrayHasKey( 'type', $properties );
+
+		$this->assertEquals( '127.0.0.1', $properties['author_ip']['default'] );
+		$this->assertEquals( 0, $properties['parent']['default'] );
+		$this->assertEquals( 0, $properties['post']['default'] );
 	}
 
 	public function test_get_item_schema_show_avatar() {
@@ -1741,15 +1849,15 @@
 	public function test_get_additional_field_registration() {
 
 		$schema = array(
-			'type'        => 'integer',
+			'type'		=> 'integer',
 			'description' => 'Some integer of mine',
-			'enum'        => array( 1, 2, 3, 4 ),
-			'context'     => array( 'view', 'edit' ),
+			'enum'		=> array( 1, 2, 3, 4 ),
+			'context'	 => array( 'view', 'edit' ),
 		);
 
 		register_rest_field( 'comment', 'my_custom_int', array(
-			'schema'          => $schema,
-			'get_callback'    => array( $this, 'additional_field_get_callback' ),
+			'schema'		  => $schema,
+			'get_callback'	=> array( $this, 'additional_field_get_callback' ),
 			'update_callback' => array( $this, 'additional_field_update_callback' ),
 		) );
 
@@ -1769,7 +1877,7 @@
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments/' . self::$approved_id );
 		$request->set_body_params(array(
 			'my_custom_int' => 123,
-			'content'       => 'abc',
+			'content'	   => 'abc',
 		));
 
 		wp_set_current_user( 1 );
@@ -1779,9 +1887,9 @@
 		$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
 		$request->set_body_params(array(
 			'my_custom_int' => 123,
-			'title'         => 'hello',
-			'content'       => 'goodbye',
-			'post'          => self::$post_id,
+			'title'		 => 'hello',
+			'content'	   => 'goodbye',
+			'post'		  => self::$post_id,
 		));
 
 		$response = $this->server->dispatch( $request );
@@ -1794,15 +1902,15 @@
 
 	public function test_additional_field_update_errors() {
 		$schema = array(
-			'type'        => 'integer',
+			'type'		=> 'integer',
 			'description' => 'Some integer of mine',
-			'enum'        => array( 1, 2, 3, 4 ),
-			'context'     => array( 'view', 'edit' ),
+			'enum'		=> array( 1, 2, 3, 4 ),
+			'context'	 => array( 'view', 'edit' ),
 		);
 
 		register_rest_field( 'comment', 'my_custom_int', array(
-			'schema'          => $schema,
-			'get_callback'    => array( $this, 'additional_field_get_callback' ),
+			'schema'		  => $schema,
+			'get_callback'	=> array( $this, 'additional_field_get_callback' ),
 			'update_callback' => array( $this, 'additional_field_update_callback' ),
 		) );
 
Index: tests/phpunit/tests/rest-api/rest-pages-controller.php
===================================================================
--- tests/phpunit/tests/rest-api/rest-pages-controller.php	(revision 39091)
+++ tests/phpunit/tests/rest-api/rest-pages-controller.php	(working copy)
@@ -95,6 +95,10 @@
 		$data = $response->get_data();
 		$this->assertEquals( 1, count( $data ) );
 		$this->assertEquals( $id2, $data[0]['id'] );
+		// Invalid parent should fail
+		$request->set_param( 'parent', 'some-slug' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_parents_query() {
@@ -129,6 +133,10 @@
 		$data = $response->get_data();
 		$this->assertEquals( 1, count( $data ) );
 		$this->assertEquals( $id1, $data[0]['id'] );
+		// Invalid parent_exclude should error
+		$request->set_param( 'parent_exclude', 'some-slug' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_menu_order_query() {
@@ -156,6 +164,11 @@
 		$this->assertEquals( $id4, $data[1]['id'] );
 		$this->assertEquals( $id2, $data[2]['id'] );
 		$this->assertEquals( $id3, $data[3]['id'] );
+		// Invalid menu_order should fail
+		$request = new WP_REST_Request( 'GET', '/wp/v2/pages' );
+		$request->set_param( 'menu_order', 'top-first' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_min_max_pages_query() {
@@ -234,7 +247,7 @@
 
 		$request = new WP_REST_Request( 'POST', '/wp/v2/pages' );
 		$params = $this->set_post_data( array(
-			'template'       => 'page-my-test-template.php',
+			'template'	   => 'page-my-test-template.php',
 		) );
 		$request->set_body_params( $params );
 		$response = $this->server->dispatch( $request );
@@ -301,8 +314,8 @@
 
 		$request = new WP_REST_Request( 'GET', '/wp/v2/pages' );
 		$request->set_query_params( array(
-			'page'           => 2,
-			'per_page'       => 4,
+			'page'		   => 2,
+			'per_page'	   => 4,
 		) );
 		$response = $this->server->dispatch( $request );
 
@@ -360,7 +373,7 @@
 
 	public function test_get_page_with_password() {
 		$page_id = $this->factory->post->create( array(
-			'post_type'     => 'page',
+			'post_type'	 => 'page',
 			'post_password' => '$inthebananastand',
 		) );
 
@@ -376,7 +389,7 @@
 
 	public function test_get_page_with_password_using_password() {
 		$page_id = $this->factory->post->create( array(
-			'post_type'     => 'page',
+			'post_type'	 => 'page',
 			'post_password' => '$inthebananastand',
 			'post_content'  => 'Some secret content.',
 			'post_excerpt'  => 'Some secret excerpt.',
@@ -396,7 +409,7 @@
 
 	public function test_get_page_with_password_using_incorrect_password() {
 		$page_id = $this->factory->post->create( array(
-			'post_type'     => 'page',
+			'post_type'	 => 'page',
 			'post_password' => '$inthebananastand',
 		) );
 
@@ -410,7 +423,7 @@
 
 	public function test_get_page_with_password_without_permission() {
 		$page_id = $this->factory->post->create( array(
-			'post_type'     => 'page',
+			'post_type'	 => 'page',
 			'post_password' => '$inthebananastand',
 			'post_content'  => 'Some secret content.',
 			'post_excerpt'  => 'Some secret excerpt.',
Index: tests/phpunit/tests/rest-api/rest-posts-controller.php
===================================================================
--- tests/phpunit/tests/rest-api/rest-posts-controller.php	(revision 39091)
+++ tests/phpunit/tests/rest-api/rest-posts-controller.php	(working copy)
@@ -92,6 +92,7 @@
 			'author_exclude',
 			'before',
 			'categories',
+			'categories_exclude',
 			'context',
 			'exclude',
 			'include',
@@ -105,6 +106,7 @@
 			'status',
 			'sticky',
 			'tags',
+			'tags_exclude',
 			), $keys );
 	}
 
@@ -183,6 +185,11 @@
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertNotEquals( self::$editor_id, $data[0]['author'] );
 		$this->assertNotEquals( self::$editor_id, $data[1]['author'] );
+		// invalid author_exclude errors
+		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
+		$request->set_param( 'author_exclude', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_include_query() {
@@ -202,6 +209,11 @@
 		$data = $response->get_data();
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( $id1, $data[0]['id'] );
+		// Invalid include should error
+		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
+		$request->set_param( 'include', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_exclude_query() {
@@ -224,6 +236,10 @@
 		$data = $response->get_data();
 		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
 		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
+
+		$request->set_param( 'exclude', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_search_query() {
@@ -316,6 +332,15 @@
 		$response = $this->server->dispatch( $request );
 		$data = $response->get_data();
 		$this->assertEquals( 'Apple Cobbler', $data[0]['title']['rendered'] );
+		// order=>asc,id should fail
+		$request->set_param( 'order', 'asc,id' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+		// orderby=>content should fail (invalid param test)
+		$request->set_param( 'order', 'asc' );
+		$request->set_param( 'orderby', 'content' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_with_orderby_relevance() {
@@ -366,6 +391,10 @@
 		$request->set_param( 'page', 3 );
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 2, $response->get_data() );
+		// Invalid 'offset' should error
+		$request->set_param( 'offset', 'moreplease' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_tags_query() {
@@ -422,6 +451,10 @@
 
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 1, $response->get_data() );
+
+		$request->set_param( 'tags', array( 'my-tag' ) );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_tags_and_categories_exclude_query() {
@@ -444,6 +477,10 @@
 		$data = $response->get_data();
 		$this->assertCount( 1, $data );
 		$this->assertEquals( $id2, $data[0]['id'] );
+
+		$request->set_param( 'tags_exclude', array( 'my-tag' ) );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_sticky_query() {
@@ -461,6 +498,10 @@
 		$posts = $response->get_data();
 		$post = $posts[0];
 		$this->assertEquals( $id2, $post['id'] );
+
+		$request->set_param( 'sticky', 'nothanks' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_sticky_with_post__in_query() {
@@ -1899,7 +1940,7 @@
 		$response = $this->server->dispatch( $request );
 		$data = $response->get_data();
 		$properties = $data['schema']['properties'];
-		$this->assertEquals( 25, count( $properties ) );
+		$this->assertEquals( 23, count( $properties ) );
 		$this->assertArrayHasKey( 'author', $properties );
 		$this->assertArrayHasKey( 'comment_status', $properties );
 		$this->assertArrayHasKey( 'content', $properties );
@@ -1922,9 +1963,7 @@
 		$this->assertArrayHasKey( 'title', $properties );
 		$this->assertArrayHasKey( 'type', $properties );
 		$this->assertArrayHasKey( 'tags', $properties );
-		$this->assertArrayHasKey( 'tags_exclude', $properties );
 		$this->assertArrayHasKey( 'categories', $properties );
-		$this->assertArrayHasKey( 'categories_exclude', $properties );
 	}
 
 	public function test_get_additional_field_registration() {
Index: tests/phpunit/tests/rest-api/rest-tags-controller.php
===================================================================
--- tests/phpunit/tests/rest-api/rest-tags-controller.php	(revision 39091)
+++ tests/phpunit/tests/rest-api/rest-tags-controller.php	(working copy)
@@ -98,6 +98,10 @@
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( 'Season 5', $data[0]['name'] );
 		$this->assertEquals( 'The Be Sharps', $data[1]['name'] );
+		// invalid value should fail
+		$request->set_param( 'hide_empty', 'nothanks' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_include_query() {
@@ -117,6 +121,10 @@
 		$data = $response->get_data();
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( $id3, $data[0]['id'] );
+		// Include invalid value shoud fail
+		$request->set_param( 'include', array( 'myterm' ) );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_exclude_query() {
@@ -132,6 +140,10 @@
 		$data = $response->get_data();
 		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
 		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
+		// Invalid exclude value should fail
+		$request->set_param( 'exclude', array( 'invalid' ) );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_offset_query() {
@@ -151,6 +163,10 @@
 		$request->set_param( 'page', 3 );
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 2, $response->get_data() );
+		// 'offset' invalid value shoudl fail
+		$request->set_param( 'offset', 'moreplease' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 
@@ -181,6 +197,10 @@
 		$data = $response->get_data();
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( 'Apple', $data[0]['name'] );
+		// Invalid orderby should fail.
+		$request->set_param( 'orderby', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_orderby_id() {
@@ -231,6 +251,12 @@
 		$data = $response->get_data();
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( 'DC', $data[0]['name'] );
+
+		// Invalid post should error.
+		$request = new WP_REST_Request( 'GET', '/wp/v2/tags' );
+		$request->set_param( 'post', 'invalid-post' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_terms_post_args_paging() {
Index: tests/phpunit/tests/rest-api/rest-users-controller.php
===================================================================
--- tests/phpunit/tests/rest-api/rest-users-controller.php	(revision 39091)
+++ tests/phpunit/tests/rest-api/rest-users-controller.php	(working copy)
@@ -363,6 +363,20 @@
 		$this->assertErrorResponse( 'rest_forbidden_orderby', $response, 401 );
 	}
 
+	public function test_get_items_invalid_order() {
+		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
+		$request->set_param( 'order', 'asc,id' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
+	public function test_get_items_invalid_orderby() {
+		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
+		$request->set_param( 'orderby', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
 	public function test_get_items_offset() {
 		wp_set_current_user( self::$user );
 		// 2 users created in __construct(), plus default user
@@ -379,6 +393,10 @@
 		$request->set_param( 'page', 3 );
 		$response = $this->server->dispatch( $request );
 		$this->assertCount( 2, $response->get_data() );
+		// 'offset' invalid value should error
+		$request->set_param( 'offset', 'moreplease' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_include_query() {
@@ -399,7 +417,12 @@
 		$data = $response->get_data();
 		$this->assertEquals( 2, count( $data ) );
 		$this->assertEquals( $id3, $data[0]['id'] );
+		// Invalid include should fail
+		$request->set_param( 'include', 'invalid' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 		// No privileges
+		$request->set_param( 'include', array( $id3, $id1 ) );
 		wp_set_current_user( 0 );
 		$response = $this->server->dispatch( $request );
 		$data = $response->get_data();
@@ -421,6 +444,10 @@
 		$data = $response->get_data();
 		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
 		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
+		// Invalid exlude value should error.
+		$request->set_param( 'exclude', 'none-of-those-please' );
+		$response = $this->server->dispatch( $request );
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
 	}
 
 	public function test_get_items_search() {
