diff --git src/wp-includes/rest-api/class-wp-rest-request.php src/wp-includes/rest-api/class-wp-rest-request.php
index 3c465babd..0022eae7e 100644
--- src/wp-includes/rest-api/class-wp-rest-request.php
+++ src/wp-includes/rest-api/class-wp-rest-request.php
@@ -669,7 +669,13 @@ class WP_REST_Request implements ArrayAccess {
 			return true;
 		}
 
-		$params = json_decode( $this->get_body(), true );
+		// Allow an empty body. See https://core.trac.wordpress.org/ticket/39150.
+		$body = $this->get_body();
+		if ( empty( $body ) ) {
+			return true;
+		}
+
+		$params = json_decode( $body, true );
 
 		/*
 		 * Check for a parsing error.
diff --git tests/phpunit/tests/rest-api/rest-request.php tests/phpunit/tests/rest-api/rest-request.php
index de44844bf..5d9f2e1fc 100644
--- tests/phpunit/tests/rest-api/rest-request.php
+++ tests/phpunit/tests/rest-api/rest-request.php
@@ -10,6 +10,10 @@
  * @group restapi
  */
 class Tests_REST_Request extends WP_UnitTestCase {
+
+	/** @var  WP_REST_Request */
+	public $request;
+
 	public function setUp() {
 		parent::setUp();
 
@@ -414,6 +418,19 @@ class Tests_REST_Request extends WP_UnitTestCase {
 		$this->assertEquals( JSON_ERROR_SYNTAX, $data['json_error_code'] );
 	}
 
+
+	public function test_has_valid_params_empty_json_no_error() {
+		if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
+			return $this->markTestSkipped( 'JSON validation is only available for PHP 5.3+' );
+		}
+
+		$this->request->set_header( 'Content-Type', 'application/json' );
+		$this->request->set_body( '' );
+
+		$valid = $this->request->has_valid_params();
+		$this->assertNotWPError( $valid );
+	}
+
 	public function test_has_multiple_invalid_params_validate_callback() {
 		$this->request->set_url_params( array(
 			'someinteger' => '123',
