Index: trac/web/api.py
===================================================================
--- trac/web/api.py	(revision 3686)
+++ trac/web/api.py	(working copy)
@@ -467,8 +467,8 @@
     requests, before and/or after they are processed by the main handler."""
 
     def pre_process_request(req, handler):
-        """Do any pre-processing the request might need; typically adding
-        values to req.hdf, or redirecting.
+        """Called after initial handler selection, and can be used to change
+        the selected handler or redirect request.
         
         Always returns the request handler, even if unchanged.
         """
Index: trac/web/main.py
===================================================================
--- trac/web/main.py	(revision 3686)
+++ trac/web/main.py	(working copy)
@@ -201,6 +201,7 @@
         # Prepare HDF for the clearsilver template
         try:
             use_template = getattr(chosen_handler, 'use_template', True)
+            req.hdf = None
             if use_template:
                 chrome = Chrome(self.env)
                 req.hdf = HDFWrapper(loadpaths=chrome.get_all_templates_dirs())
@@ -211,21 +212,35 @@
             if not early_error:
                 raise
 
+        def post_process_request(resp=(None, None)):
+            for filter_ in reversed(self.filters):
+                resp = filter_.post_process_request(req, *resp)
+            return resp
+
+        def post_process_after_error():
+            try:
+                post_process_request()
+            except Exception, e:
+                self.log.exception(e)
+
         if early_error:
+            post_process_after_error()
             raise early_error[0], early_error[1], early_error[2]
 
         # Process the request and render the template
         try:
             try:
-                resp = chosen_handler.process_request(req)
-                if resp:
-                    for filter_ in reversed(self.filters):
-                        resp = filter_.post_process_request(req, *resp)
-                    template, content_type = resp
-                    req.display(template, content_type or 'text/html')
-                else:
-                    for filter_ in reversed(self.filters):
-                        filter_.post_process_request(req, None, None)
+                try:
+                    resp = chosen_handler.process_request(req)
+                    if resp:
+                        template, content_type = post_process_request(resp)
+                        req.display(template, content_type or 'text/html')
+                    else:
+                        post_process_request()
+                except:
+                    post_process_after_error()
+                    err = sys.exc_info()
+                    raise err[0], err[1], err[2]
             except PermissionError, e:
                 raise HTTPForbidden(to_unicode(e))
             except TracError, e:

