diff --git a/trac/ticket/report.py b/trac/ticket/report.py
--- a/trac/ticket/report.py
+++ b/trac/ticket/report.py
@@ -34,7 +34,8 @@
 from trac.util.text import to_unicode, unicode_urlencode
 from trac.util.translation import _
 from trac.web.api import IRequestHandler, RequestDone
-from trac.web.chrome import add_ctxtnav, add_link, add_stylesheet, \
+from trac.web.chrome import add_ctxtnav, add_link, add_script, \
+                            add_stylesheet, add_warning, \
                             INavigationContributor, Chrome
 from trac.wiki import IWikiSyntaxProvider, WikiParser
 
@@ -219,11 +220,6 @@
 
     def _render_view(self, req, db, id):
         """Retrieve the report results and pre-process them for rendering."""
-        try:
-            args = self.get_var_args(req)
-        except ValueError,e:
-            raise TracError(_('Report failed: %(error)s', error=e))
-
         if id == -1:
             # If no particular report was requested, display
             # a list of available reports instead
@@ -241,6 +237,11 @@
                 raise ResourceNotFound(
                     _('Report %(num)s does not exist.', num=id),
                     _('Invalid Report Number'))
+
+        try:
+            args = self.get_var_args(req)
+        except ValueError,e:
+            raise TracError(_('Report failed: %(error)s', error=e))
 
         # If this is a saved custom query. redirect to the query module
         #
@@ -294,8 +295,9 @@
         user = req.args.get('USER', None)
 
         try:
-            cols, results, num_items = self.execute_paginated_report(
-                    req, db, id, sql, args, limit, offset)
+            cols, results, num_items, missing_args = \
+                self.execute_paginated_report(req, db, id, sql, args, limit,
+                                              offset)
             results = [list(row) for row in results]
             numrows = len(results)
 
@@ -497,6 +499,12 @@
                             del req.session[var]
                 except (ValueError, KeyError):
                     pass
+            if len(data['args']) > 1:
+                add_script(req, 'common/js/folding.js')
+            if missing_args:
+                add_warning(req, _(
+                    'The following arguments are missing: %(args)s',
+                    args=", ".join(missing_args)))
             return 'report_view.html', data, None
 
     def add_alternate_links(self, req, args):
@@ -527,7 +535,7 @@
 
     def execute_paginated_report(self, req, db, id, sql, args, 
                                  limit=0, offset=0):
-        sql, args = self.sql_sub_vars(sql, args, db)
+        sql, args, missing_args = self.sql_sub_vars(sql, args, db)
         if not sql:
             raise TracError(_('Report %(num)s has no SQL query.', num=id))
         self.log.debug('Executing report with SQL "%s"' % sql)
@@ -579,7 +587,7 @@
 
         db.rollback()
 
-        return cols, info, num_items
+        return cols, info, num_items, missing_args
 
     def get_var_args(self, req):
         report_args = {}
@@ -598,12 +606,13 @@
         if db is None:
             db = self.env.get_db_cnx()
         values = []
+        missing_args = []
         def add_value(aname):
             try:
                 arg = args[aname]
             except KeyError:
-                raise TracError(_("Dynamic variable '%(name)s' not defined.",
-                                  name='$%s' % aname))
+                arg = args[str(aname)] = ''
+                missing_args.append(aname)
             values.append(arg)
 
         var_re = re.compile("[$]([A-Z]+)")
@@ -634,7 +643,7 @@
                 sql_io.write(repl_literal(expr))
             else:
                 sql_io.write(var_re.sub(repl, expr))
-        return sql_io.getvalue(), values
+        return sql_io.getvalue(), values, missing_args
 
     def _send_csv(self, req, cols, rows, sep=',', mimetype='text/plain',
                   filename=None):
diff --git a/trac/ticket/templates/report_view.html b/trac/ticket/templates/report_view.html
--- a/trac/ticket/templates/report_view.html
+++ b/trac/ticket/templates/report_view.html
@@ -7,11 +7,15 @@
   <xi:include href="layout.html" />
   <head>
     <title>$title</title>
+    <script type="text/javascript" py:if="report.id != -1 and len(args) > 1">
+      jQuery(document).ready(function($) {
+        $("fieldset legend").enableFolding(false);
+      });
+    </script>
   </head>
 
   <body>
     <div id="content" class="report">
-
       <h1>$title
         <span py:if="numrows and report.id != -1" class="numrows">($numrows matches)</span>
       </h1>
@@ -19,6 +23,32 @@
       <div py:if="description" id="description" xml:space="preserve">
         ${wiki_to_html(context, description)}
       </div>
+
+      <form py:if="report.id != -1 and len(args) > 1" method="get" action="">
+        <fieldset id="filters" >
+          <legend class="foldable">Arguments</legend>
+          <table summary="Report arguments">
+            <tbody>
+              <tr style="height: 1px"><td colspan="2"></td></tr>
+            </tbody>
+            <tbody py:for="arg in args" py:if="arg != 'USER'">
+              <tr>
+                <th scope="row"><label>${arg}</label></th>
+                <td class="filter">
+                  <input type="text" name="${arg}" value="${req.args[arg] or None}" size="42" />
+                </td>
+              </tr>
+            </tbody>
+            <tbody>
+              <tr class="actions">
+                <td class="actions" colspan="2" style="text-align: right">
+                  <input type="submit" value="Update" />
+                </td>
+              </tr>
+            </tbody>
+          </table>
+        </fieldset>
+      </form>
 
       <div py:if="report.id != -1" class="buttons">
         <form py:if="'REPORT_MODIFY' in perm(report.resource)" action="" method="get">

