diff --git a/jsonapi.services.yml b/jsonapi.services.yml
index 3a97096..c2088a6 100644
--- a/jsonapi.services.yml
+++ b/jsonapi.services.yml
@@ -99,3 +99,7 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@serializer', '%serializer.formats%']
+  http_middleware.format_setter:
+    class: Drupal\jsonapi\StackMiddleware\FormatSetter
+    tags:
+      - { name: http_middleware, priority: 399, responder: true }
diff --git a/src/Access/CustomQueryParameterNamesAccessCheck.php b/src/Access/CustomQueryParameterNamesAccessCheck.php
index 659115d..987c19f 100644
--- a/src/Access/CustomQueryParameterNamesAccessCheck.php
+++ b/src/Access/CustomQueryParameterNamesAccessCheck.php
@@ -25,7 +25,10 @@ class CustomQueryParameterNamesAccessCheck implements AccessInterface {
    * @return \Drupal\Core\Access\AccessResult
    *   The access result.
    */
-  public function access(Request $request) {
+  public function access(Request $request = NULL) {
+    if (!$request) {
+      return AccessResult::neutral();
+    }
     $json_api_params = $request->attributes->get('_json_api_params', []);
     if (!$this->validate($json_api_params)) {
       return AccessResult::forbidden();
diff --git a/src/EventSubscriber/DefaultExceptionSubscriber.php b/src/EventSubscriber/DefaultExceptionSubscriber.php
index 9d5467b..9070b31 100644
--- a/src/EventSubscriber/DefaultExceptionSubscriber.php
+++ b/src/EventSubscriber/DefaultExceptionSubscriber.php
@@ -4,6 +4,7 @@ namespace Drupal\jsonapi\EventSubscriber;
 
 use Drupal\serialization\EventSubscriber\DefaultExceptionSubscriber as SerializationDefaultExceptionSubscriber;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
 use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -33,8 +34,7 @@ class DefaultExceptionSubscriber extends SerializationDefaultExceptionSubscriber
   public function onException(GetResponseForExceptionEvent $event) {
     /** @var \Symfony\Component\HttpKernel\Exception\HttpException $exception */
     $exception = $event->getException();
-    $route = $event->getRequest()->get(RouteObjectInterface::ROUTE_OBJECT);
-    if (!$route || !$route->getOption('_is_jsonapi')) {
+    if (!$this->isJsonApiFormatted($event->getRequest())) {
       return;
     }
     if (!$exception instanceof HttpException) {
@@ -51,8 +51,7 @@ class DefaultExceptionSubscriber extends SerializationDefaultExceptionSubscriber
   protected function setEventResponse(GetResponseForExceptionEvent $event, $status) {
     /** @var \Symfony\Component\HttpKernel\Exception\HttpException $exception */
     $exception = $event->getException();
-    $route = $event->getRequest()->get(RouteObjectInterface::ROUTE_OBJECT);
-    if (!$route || !$route->getOption('_is_jsonapi')) {
+    if (!$this->isJsonApiFormatted($event->getRequest())) {
       return;
     }
     $encoded_content = $this->serializer->serialize($exception, 'api_json', ['data_wrapper' => 'errors']);
@@ -61,4 +60,21 @@ class DefaultExceptionSubscriber extends SerializationDefaultExceptionSubscriber
     $event->setResponse($response);
   }
 
+  /**
+   * Check if the error should be formatted using JSON API.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The failed request.
+   *
+   * @return bool
+   *   TRUE if it needs to be formated using JSON API. FALSE otherwise.
+   */
+  protected function isJsonApiFormatted(Request $request) {
+    $route = $request->get(RouteObjectInterface::ROUTE_OBJECT);
+    $format = $request->getRequestFormat();
+    // The JSON API format is supported if the format is explicitly set or the
+    // request is for a known JSON API route.
+    return $format == 'api_json' || ($route && $route->getOption('_is_jsonapi'));
+  }
+
 }
diff --git a/src/StackMiddleware/FormatSetter.php b/src/StackMiddleware/FormatSetter.php
new file mode 100644
index 0000000..4fa64f5
--- /dev/null
+++ b/src/StackMiddleware/FormatSetter.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\jsonapi\StackMiddleware;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * If the request belongs to a JSON API managed route, then sets the api_json
+ * format manually.
+ */
+class FormatSetter implements HttpKernelInterface {
+
+  /**
+   * The wrapped HTTP kernel.
+   *
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   */
+  protected $httpKernel;
+
+  /**
+   * Constructs a PageCache object.
+   *
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
+   *   The decorated kernel.
+   */
+  public function __construct(HttpKernelInterface $http_kernel) {
+    $this->httpKernel = $http_kernel;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    // Check if the accept header is set to the official header.
+    $accept = $request->headers->get('Accept');
+    if (strpos($accept, 'application/vnd.api+json') !== FALSE) {
+      // Manually set the format.
+      $request->setRequestFormat('api_json');
+    }
+
+    return $this->httpKernel->handle($request, $type, $catch);
+  }
+
+}
diff --git a/tests/src/Functional/JsonApiFunctionalTest.php b/tests/src/Functional/JsonApiFunctionalTest.php
index 869d3f1..6ccfb78 100644
--- a/tests/src/Functional/JsonApiFunctionalTest.php
+++ b/tests/src/Functional/JsonApiFunctionalTest.php
@@ -244,6 +244,21 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
     ]));
     $this->assertSession()->statusCodeEquals(200);
     $this->assertGreaterThanOrEqual(1, count($single_output['data']));
+    // 19. Test non-existing route without negotiation header.
+    $this->drupalGet('/jsonapi/node/article/broccoli');
+    $this->assertSession()->statusCodeEquals(404);
+    // Without the Accept header we cannot know we want the 404 error formatted
+    // as JSON API.
+    $this->assertSession()->responseHeaderContains('Content-Type', 'text/html');
+    // 20. Test non-existing route with negotiation header.
+    $single_output = Json::decode($this->drupalGet('/jsonapi/node/article/broccoli', [], [
+      'Accept' => 'application/vnd.api+json',
+    ]));
+    $this->assertEquals(404, $single_output['errors'][0]['status']);
+    $this->assertSession()->statusCodeEquals(404);
+    // With the Accept header we can know we want the 404 error formatted as
+    // JSON API.
+    $this->assertSession()->responseHeaderContains('Content-Type', 'application/vnd.api+json');
   }
 
   /**
