diff --git a/Base/Axis/Scale.cpp b/Base/Axis/Scale.cpp
index 25575d914c22f34220492ea38fbe6a46af81c491..cb69ee1a76ea639fbbf139af7f2d56ad069ce52e 100644
--- a/Base/Axis/Scale.cpp
+++ b/Base/Axis/Scale.cpp
@@ -17,20 +17,30 @@
 #include <iomanip>
 #include <iostream>
 #include <numbers>
+#include <stdexcept>
 using std::numbers::pi;
 
 Scale::Scale(const Coordinate& coord, std::vector<Bin1D> bins)
     : m_coord(coord)
     , m_bins(std::move(bins))
 {
-    ASSERT(size() > 0);
+    if (size() == 0)
+        throw std::runtime_error("Scale constructor called with no bins");
     for (size_t i = 0; i < size() - 1; ++i) {
-        ASSERT(bin(i).upperBound() <= bin(i + 1).lowerBound()); // bins must not overlap
-        ASSERT(bin(i) != bin(i + 1));                           // bins must not repeat
+        if (bin(i).upperBound() > bin(i + 1).lowerBound())
+            throw std::runtime_error("Scale constructor called with overlapping bins");
+        if (bin(i) == bin(i + 1))
+            throw std::runtime_error("Scale constructor called with repeating bin(s)");
     }
-    if (isScan())
+    if (isScan()) {
         for (const Bin1D& b : m_bins)
-            ASSERT(!b.binSize()); // bin widths must be all zero or all positive
+            if (b.binSize() != 0)
+                throw std::runtime_error("Finite bin(s) in scan");
+    } else {
+        for (const Bin1D& b : m_bins)
+            if (b.binSize() == 0)
+                throw std::runtime_error("Empty bin(s) in sweep");
+    }
 }
 
 std::string Scale::axisLabel() const