diff --git a/arbor/backends/multicore/matrix_state.hpp b/arbor/backends/multicore/matrix_state.hpp
index 24a21c1b5bc8beddf4781547b892bedbd33a80d3..1831bfa07c221c26a28b8e71104262e4add0faa2 100644
--- a/arbor/backends/multicore/matrix_state.hpp
+++ b/arbor/backends/multicore/matrix_state.hpp
@@ -58,13 +58,15 @@ public:
 
         auto n = size();
         invariant_d = array(n, 0);
-        for (auto i: util::make_span(1u, n)) {
-            auto gij = face_conductance[i];
-
-            u[i] = -gij;
-            invariant_d[i] += gij;
-            if (p[i]!=-1) {
-                invariant_d[p[i]] += gij;
+        if (n >= 1) { // skip empty matrix, ie cell with empty morphology
+            for (auto i: util::make_span(1u, n)) {
+                auto gij = face_conductance[i];
+
+                u[i] = -gij;
+                invariant_d[i] += gij;
+                if (p[i]!=-1) {
+                    invariant_d[p[i]] += gij;
+                }
             }
         }
     }
@@ -116,7 +118,7 @@ public:
         for (auto cv_span: util::partition_view(cell_cv_divs)) {
             auto first = cv_span.first;
             auto last = cv_span.second; // one past the end
-
+            if (first >= last) continue; // skip cell with no CVs
             if (d[first]!=0) {
                 // backward sweep
                 for(auto i=last-1; i>first; --i) {
diff --git a/arbor/util/span.hpp b/arbor/util/span.hpp
index c6599e163f15698b64c384567efd5bb5fbd28224..06cc4bcd4d0795b3ffd69e81521de82762b793bd 100644
--- a/arbor/util/span.hpp
+++ b/arbor/util/span.hpp
@@ -22,24 +22,24 @@ namespace util {
 template <typename I>
 using span = range<counter<I>>;
 
-template <typename I, typename J>
+template <typename I, typename J, typename = std::enable_if_t<std::is_integral<std::common_type_t<I, J>>::value>>
 span<std::common_type_t<I, J>> make_span(I left, J right) {
     return span<std::common_type_t<I, J>>(left, right);
 }
 
 template <typename I, typename J>
 span<std::common_type_t<I, J>> make_span(std::pair<I, J> interval) {
-    return span<std::common_type_t<I, J>>(interval.first, interval.second);
+    return make_span(interval.first, interval.second);
 }
 
 template <typename I>
 span<I> make_span(I right) {
-    return span<I>(I{}, right);
+    return make_span(I{}, right);
 }
 
 template <typename Seq>
 auto count_along(const Seq& s) {
-    return util::make_span(std::size(s));
+    return make_span(std::size(s));
 }
 
 } // namespace util
diff --git a/test/unit/test_simulation.cpp b/test/unit/test_simulation.cpp
index 569c4fa403889cc5dc3cdfba762d3d3de0692d8f..3110d43822af939061ea6422bf77531a6c377589 100644
--- a/test/unit/test_simulation.cpp
+++ b/test/unit/test_simulation.cpp
@@ -2,8 +2,11 @@
 
 #include <random>
 #include <vector>
+#include <any>
 
+#include <arbor/cable_cell.hpp>
 #include <arbor/common_types.hpp>
+#include <arbor/context.hpp>
 #include <arbor/domain_decomposition.hpp>
 #include <arbor/load_balance.hpp>
 #include <arbor/lif_cell.hpp>
@@ -33,6 +36,25 @@ static auto n_thread_context(unsigned n_thread) {
     return make_context(proc_allocation(std::max((int)n_thread, 1), -1));
 }
 
+struct null_recipe: arb::recipe {
+    arb::cable_cell_global_properties properties;
+    null_recipe() { properties.default_parameters = arb::neuron_parameter_defaults; }
+    arb::cell_size_type num_cells() const override { return 1; }
+    arb::cell_kind get_cell_kind(arb::cell_gid_type) const override { return arb::cell_kind::cable; }
+    arb::util::unique_any get_cell_description(arb::cell_gid_type) const override { return {arb::cable_cell{}}; }
+    std::vector<arb::probe_info> get_probes(arb::cell_gid_type gid) const override { return {}; }
+    std::any get_global_properties(arb::cell_kind) const override { return properties; }
+};
+
+// Test that cell models with empty morpologies build and run without error.
+TEST(simulation, null) {
+    auto r = null_recipe{};
+    auto c = arb::make_context();
+    auto d = arb::partition_load_balance(r, c);
+    auto s = arb::simulation(r, d, c);
+    s.run(0.05, 0.01);
+}
+
 TEST(simulation, spike_global_callback) {
     constexpr unsigned n = 5;
     double t_max = 10.;
diff --git a/test/unit/test_span.cpp b/test/unit/test_span.cpp
index 6c55aeade259d722e84e2c14c52f1a3415badb88..7447e93366ef8ee18184f1cb73c17c0c8068de7a 100644
--- a/test/unit/test_span.cpp
+++ b/test/unit/test_span.cpp
@@ -40,7 +40,7 @@ TEST(span, int_access) {
 
 TEST(span, int_iterators) {
     using span = util::span<int>;
-
+    using uc_span = util::span<unsigned char>;
     int n = 97;
     int a = 3;
     int b = a+n;
@@ -53,11 +53,29 @@ TEST(span, int_iterators) {
     EXPECT_EQ(n, std::distance(s.begin(), s.end()));
     EXPECT_EQ(n, std::distance(s.cbegin(), s.cend()));
 
-    int sum = 0;
-    for (auto i: span(a, b)) {
-        sum += i;
+    {
+        int sum = 0;
+        for (auto i: span(a, b)) {
+            sum += i;
+        }
+        EXPECT_EQ(sum, (a+b-1)*(b-a)/2);
+    }
+
+    {
+        auto touched = 0ul;
+        auto s = uc_span(b, a);
+        for (auto _: s) ++touched;
+        EXPECT_EQ(s.size(), touched);
+        EXPECT_GT(touched, 0ul); //
+    }
+
+    {
+        auto touched = 0ul;
+        auto s = uc_span(a, a);
+        for (auto _: s) ++touched;
+        EXPECT_EQ(s.size(), touched);
+        EXPECT_EQ(0ul, touched);
     }
-    EXPECT_EQ(sum, (a+b-1)*(b-a)/2);
 }
 
 TEST(span, make_span) {