diff --git a/MEMO b/MEMO
index 1b1dd69af807f0823cebf0ff43d1f5033fa927ff..a83ca749162e9af2cf8fbe7789dd312a97f0fb7d 100644
--- a/MEMO
+++ b/MEMO
@@ -70,6 +70,10 @@ To-do
 
 - Test array access with modulo
 
+- Derive all errors from central hierarchy
+
+- Provide context for more errors?
+
 Fixes:
 
 - applied_iname_rewrites tracking for prefetch footprints isn't bulletproof
diff --git a/loopy/__init__.py b/loopy/__init__.py
index 45d65683bad3913ccd5e7be082bd9c701d6b783f..e81ba1ebb3fb1959ccf5a192f9166b454100eb3b 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -39,9 +39,6 @@ from pytools import MovedFunctionDeprecationWrapper
 from loopy.symbolic import ExpandingIdentityMapper, ExpandingSubstitutionMapper
 
 
-class LoopyAdvisory(UserWarning):
-    pass
-
 # {{{ imported user interface
 
 from loopy.kernel.data import (
@@ -346,9 +343,12 @@ def join_inames(kernel, inames, new_iname=None, tag=None, within=None):
 
         length = int(pw_aff_to_expr(
             static_max_of_pw_aff(bounds.size, constants_only=True)))
-        lower_bound_aff = static_value_of_pw_aff(
-                bounds.lower_bound_pw_aff.coalesce(),
-                constants_only=False)
+        try:
+            lower_bound_aff = static_value_of_pw_aff(
+                    bounds.lower_bound_pw_aff.coalesce(),
+                    constants_only=False)
+        except Exception, e:
+            raise type(e)("while finding lower bound of '%s': " % iname)
 
         my_val = var(new_iname) // base_divisor
         if i+1 < len(inames):
diff --git a/loopy/check.py b/loopy/check.py
index 87fcb1e862ec15366c33f09ea0607300e9c4d199..fefd150d85fa55b124c69a16b38fb79b6e73e42e 100644
--- a/loopy/check.py
+++ b/loopy/check.py
@@ -36,7 +36,7 @@ logger = logging.getLogger(__name__)
 def check_sizes(kernel):
     import loopy as lp
 
-    from loopy import LoopyAdvisory
+    from loopy.diagnostic import LoopyAdvisory
 
     parameters = {}
     for arg in kernel.args:
diff --git a/loopy/codegen/loop.py b/loopy/codegen/loop.py
index 60836279f9f44cf8e3fbf77bf39a9e7fd17930c5..f94a256e86d16e659d3b24a1522554890476e2f0 100644
--- a/loopy/codegen/loop.py
+++ b/loopy/codegen/loop.py
@@ -124,9 +124,13 @@ def generate_unroll_loop(kernel, sched_index, codegen_state):
 
     length = int(pw_aff_to_expr(
         static_max_of_pw_aff(bounds.size, constants_only=True)))
-    lower_bound_aff = static_value_of_pw_aff(
-            bounds.lower_bound_pw_aff.coalesce(),
-            constants_only=False)
+
+    try:
+        lower_bound_aff = static_value_of_pw_aff(
+                bounds.lower_bound_pw_aff.coalesce(),
+                constants_only=False)
+    except Exception, e:
+        raise type(e)("while finding lower bound of '%s': " % iname)
 
     result = []
 
diff --git a/loopy/compiled.py b/loopy/compiled.py
index ae443679bc7c812770cdad7bcd7cd7b58896f647..d3eb8ab52ca8fc502d41c403468865c88162ffcf 100644
--- a/loopy/compiled.py
+++ b/loopy/compiled.py
@@ -27,10 +27,7 @@ import pyopencl as cl
 import pyopencl.tools  # noqa
 import numpy as np
 from pytools import Record, memoize_method
-
-
-class ParameterFinderWarning(UserWarning):
-    pass
+from loopy.diagnostic import ParameterFinderWarning
 
 
 # {{{ object array argument packing
diff --git a/loopy/diagnostic.py b/loopy/diagnostic.py
new file mode 100644
index 0000000000000000000000000000000000000000..299b3564f249d07c7aaf3b8523fe814af2622a2d
--- /dev/null
+++ b/loopy/diagnostic.py
@@ -0,0 +1,47 @@
+from __future__ import division
+
+__copyright__ = "Copyright (C) 2012 Andreas Kloeckner"
+
+__license__ = """
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+
+# {{{ warnings
+
+class LoopyWarningBase(UserWarning):
+    pass
+
+
+class LoopyAdvisory(LoopyWarningBase):
+    pass
+
+
+class ParameterFinderWarning(LoopyWarningBase):
+    pass
+
+# }}}
+
+# {{{ errors
+
+# FIXME
+
+# }}}
+
+# vim: foldmethod=marker
diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py
index dd1da75324f0994e460ce8eef38851eff5cbd5b3..d9b8169abc728ff9197b9d0416d2e14ff57548b8 100644
--- a/loopy/kernel/tools.py
+++ b/loopy/kernel/tools.py
@@ -214,8 +214,6 @@ class SetOperationCacheManager:
         else:
             idx = iname
 
-        del iname
-
         lower_bound_pw_aff = self.dim_min(set, idx)
         upper_bound_pw_aff = self.dim_max(set, idx)
 
@@ -225,9 +223,12 @@ class SetOperationCacheManager:
         size = pw_aff_to_expr(static_max_of_pw_aff(
                 upper_bound_pw_aff - lower_bound_pw_aff + 1, constants_only=True,
                 context=context))
-        base_index = pw_aff_to_expr(
-            static_value_of_pw_aff(lower_bound_pw_aff, constants_only=False,
-                context=context))
+        try:
+            base_index = pw_aff_to_expr(
+                    static_value_of_pw_aff(lower_bound_pw_aff, constants_only=False,
+                        context=context))
+        except Exception, e:
+            raise type(e)("while finding lower bound of '%s': " % iname)
 
         return base_index, size
 
diff --git a/loopy/preprocess.py b/loopy/preprocess.py
index fe6827f5c382beeb720b083af58f76064dc0bea4..fb33c152cf08bc217c4011c20c2f4ccc5b9642fa 100644
--- a/loopy/preprocess.py
+++ b/loopy/preprocess.py
@@ -244,7 +244,7 @@ def mark_local_temporaries(kernel):
 
         if not wants_to_be_local_per_insn:
             from warnings import warn
-            from loopy import LoopyAdvisory
+            from loopy.diagnostic import LoopyAdvisory
             warn("temporary variable '%s' never written, eliminating"
                     % temp_var.name, LoopyAdvisory)
 
@@ -962,7 +962,7 @@ def adjust_local_temp_var_storage(kernel):
 
             if min_mult != 1:
                 from warnings import warn
-                from loopy import LoopyAdvisory
+                from loopy.diagnostic import LoopyAdvisory
                 warn("could not find a conflict-free mem layout "
                         "for local variable '%s' "
                         "(currently: %dx conflict, increment: %s, reason: %s)"
diff --git a/loopy/schedule.py b/loopy/schedule.py
index 3bcf975d9e2fbdaaeef1c8a88f7281c6e36e2bd0..75fa263fbeaf1280e5e06f114f38db10610f48d6 100644
--- a/loopy/schedule.py
+++ b/loopy/schedule.py
@@ -830,7 +830,7 @@ def generate_loop_schedules(kernel, debug_args={}):
             gen_sched, owed_barriers = insert_barriers(kernel, gen_sched)
             if owed_barriers:
                 from warnings import warn
-                from loopy import LoopyAdvisory
+                from loopy.diagnostic import LoopyAdvisory
                 warn("Barrier insertion finished without inserting barriers for "
                         "local memory writes in these instructions: '%s'. "
                         "This often means that local memory was "