Add new exceptions module, to implement JSONHttpException and JSONBadRequest.
diff --git a/CHANGES b/CHANGES
index 8311e2e758..91a31040e3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,8 @@ Version 0.9
 
 Relase date to be decided, codename to be chosen.
 
+- The :func:`flask.Request.on_json_loading_failed` now returns a JSON formatted
+  response by default.
 - The :func:`flask.url_for` function now can generate anchors to the
   generated links.
 - The :func:`flask.url_for` function now can also explicitly generate
diff --git a/flask/exceptions.py b/flask/exceptions.py
new file mode 100644
index 0000000000..9ccdedaba1
--- /dev/null
+++ b/flask/exceptions.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+"""
+    flask.exceptions
+    ~~~~~~~~~~~~
+
+    Flask specific additions to :class:`~werkzeug.exceptions.HTTPException`
+
+    :copyright: (c) 2011 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from werkzeug.exceptions import HTTPException, BadRequest
+from .helpers import json
+
+
+class JSONHTTPException(HTTPException):
+    """A base class for HTTP exceptions with ``Content-Type:
+    application/json``.
+
+    The ``description`` attribute of this class must set to a string (*not* an
+    HTML string) which describes the error.
+
+    """
+
+    def get_body(self, environ):
+        """Overrides :meth:`werkzeug.exceptions.HTTPException.get_body` to
+        return the description of this error in JSON format instead of HTML.
+
+        """
+        return json.dumps(dict(description=self.get_description(environ)))
+
+    def get_headers(self, environ):
+        """Returns a list of headers including ``Content-Type:
+        application/json``.
+
+        """
+        return [('Content-Type', 'application/json')]
+
+
+class JSONBadRequest(JSONHTTPException, BadRequest):
+    """Represents an HTTP ``400 Bad Request`` error whose body contains an
+    error message in JSON format instead of HTML format (as in the superclass).
+
+    """
+
+    #: The description of the error which occurred as a string.
+    description = (
+        'The browser (or proxy) sent a request that this server could not '
+        'understand.'
+    )
diff --git a/flask/testsuite/helpers.py b/flask/testsuite/helpers.py
index 89c6c188fc..e48f8dc392 100644
--- a/flask/testsuite/helpers.py
+++ b/flask/testsuite/helpers.py
@@ -40,6 +40,18 @@ def return_json():
         rv = c.post('/json', data='malformed', content_type='application/json')
         self.assert_equal(rv.status_code, 400)
 
+    def test_json_bad_requests_content_type(self):
+        app = flask.Flask(__name__)
+        @app.route('/json', methods=['POST'])
+        def return_json():
+            return unicode(flask.request.json)
+        c = app.test_client()
+        rv = c.post('/json', data='malformed', content_type='application/json')
+        self.assert_equal(rv.status_code, 400)
+        self.assert_equal(rv.mimetype, 'application/json')
+        self.assert_('description' in flask.json.loads(rv.data))
+        self.assert_('<p>' not in flask.json.loads(rv.data)['description'])
+
     def test_json_body_encoding(self):
         app = flask.Flask(__name__)
         app.testing = True
diff --git a/flask/wrappers.py b/flask/wrappers.py
index f6ec2788a0..541d26ef3c 100644
--- a/flask/wrappers.py
+++ b/flask/wrappers.py
@@ -10,9 +10,9 @@
 """
 
 from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase
-from werkzeug.exceptions import BadRequest
 from werkzeug.utils import cached_property
 
+from .exceptions import JSONBadRequest
 from .debughelpers import attach_enctype_error_multidict
 from .helpers import json, _assert_have_json
 from .globals import _request_ctx_stack
@@ -108,12 +108,23 @@ def json(self):
 
     def on_json_loading_failed(self, e):
         """Called if decoding of the JSON data failed.  The return value of
-        this method is used by :attr:`json` when an error ocurred.  The
-        default implementation raises a :class:`~werkzeug.exceptions.BadRequest`.
+        this method is used by :attr:`json` when an error ocurred.  The default
+        implementation raises a :class:`JSONBadRequest`, which is a subclass of
+        :class:`~werkzeug.exceptions.BadRequest` which sets the
+        ``Content-Type`` to ``application/json`` and provides a JSON-formatted
+        error description::
+
+            {"description": "The browser (or proxy) sent a request that \
+                             this server could not understand."}
+
+        .. versionchanged:: 0.9
+
+           Return a :class:`JSONBadRequest` instead of a
+           :class:`~werkzeug.exceptions.BadRequest` by default.
 
         .. versionadded:: 0.8
         """
-        raise BadRequest()
+        raise JSONBadRequest()
 
     def _load_form_data(self):
         RequestBase._load_form_data(self)

This is an update to pull request #423, to move exception classes out of wrappers.py
