diff --git a/loopy/check.py b/loopy/check.py
index 8e1709b71ae9e849fae4726b84407f504a082f4d..0390618181b70129ba0395218f9dd40f2cad803a 100644
--- a/loopy/check.py
+++ b/loopy/check.py
@@ -525,6 +525,27 @@ def check_that_temporaries_are_defined_in_subkernels_where_used(kernel):
 # }}}
 
 
+# {{{ check that all instructions are scheduled
+
+def check_that_all_insns_are_scheduled(kernel):
+    all_insns = set(insn.id for insn in kernel.instructions)
+    from loopy.schedule import sched_item_to_insn_id
+    scheduled_insns = set(
+        insn_id
+        for sched_item in kernel.schedule
+        for insn_id in sched_item_to_insn_id(sched_item))
+
+    assert scheduled_insns <= all_insns
+
+    if scheduled_insns < all_insns:
+        from loopy.diagnostic import UnscheduledInstructionError
+        raise UnscheduledInstructionError(
+            "unscheduled instructions: '%s'"
+            % ', '.join(all_insns - scheduled_insns))
+
+# }}}
+
+
 # {{{ check that shapes and strides are arguments
 
 def check_that_shapes_and_strides_are_arguments(kernel):
@@ -576,6 +597,7 @@ def pre_codegen_checks(kernel):
         check_for_unused_hw_axes_in_insns(kernel)
         check_that_atomic_ops_are_used_exactly_on_atomic_arrays(kernel)
         check_that_temporaries_are_defined_in_subkernels_where_used(kernel)
+        check_that_all_insns_are_scheduled(kernel)
         kernel.target.pre_codegen_check(kernel)
         check_that_shapes_and_strides_are_arguments(kernel)
 
diff --git a/loopy/diagnostic.py b/loopy/diagnostic.py
index e76279c27e5fab5d01b3039d0e5dcc08c2fa749e..15ab8a1ee13df440926e51e676223bc6a398df57 100644
--- a/loopy/diagnostic.py
+++ b/loopy/diagnostic.py
@@ -99,6 +99,10 @@ class MissingBarrierError(LoopyError):
 class MissingDefinitionError(LoopyError):
     pass
 
+
+class UnscheduledInstructionError(LoopyError):
+    pass
+
 # }}}
 
 
diff --git a/test/test_loopy.py b/test/test_loopy.py
index 81fe49cb42ad2dcc3c7dd69e54b758f3278a4517..30408b26e5b6ce02cb8a0b709bc8a3e7fd4f9ceb 100644
--- a/test/test_loopy.py
+++ b/test/test_loopy.py
@@ -1817,6 +1817,23 @@ def test_tight_loop_bounds_codegen():
     assert for_loop in cgr.device_code()
 
 
+def test_unscheduled_insn_detection():
+    knl = lp.make_kernel(
+        "{ [i]: 0 <= i < 10 }",
+        """
+        out[i] = i {id=insn1}
+        """,
+        "...")
+
+    knl = lp.get_one_scheduled_kernel(lp.preprocess_kernel(knl))
+    insn1, = lp.find_instructions(knl, "id:insn1")
+    knl.instructions.append(insn1.copy(id="insn2"))
+
+    from loopy.diagnostic import UnscheduledInstructionError
+    with pytest.raises(UnscheduledInstructionError):
+        lp.generate_code(knl)
+
+
 if __name__ == "__main__":
     if len(sys.argv) > 1:
         exec(sys.argv[1])