diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07c497e74357af082d0142c43a2d37e2c039c8ea..8f7f78b07e86793ad4e952f14adf321be0bff3c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,5 +36,7 @@ release.
 ## Unreleased
 
 ### Changed
-- Removed all `pyproj` calls from csm.py, abstracting them into the reprojection and pyproj.Transformer code inside utils.py. Updated the transformations to use the new pipeline style syntax to avoid deprecation warnings about old syntax.p
+- Removed all `pyproj` calls from csm.py, abstracting them into the reprojection and pyproj.Transformer code inside utils.py. Updated the transformations to use the new pipeline style syntax to avoid deprecation warnings about old syntax.
 
+### Fixed
+- Added a check to `generate_ground_point` when a GeoDataset is used to raise a `ValueError` if the algorithm intersects a no data value in the passed DEM. This ensures that valid heights are used in the intersection computation.
diff --git a/knoten/csm.py b/knoten/csm.py
index ee703142c56d4cb9eb3260429c0c932f7a8b83e6..f80753052a4b4d9c8ff55b02efd29a3e3102b348 100644
--- a/knoten/csm.py
+++ b/knoten/csm.py
@@ -157,24 +157,23 @@ def _(dem, image_pt, camera, max_its = 20, tolerance = 0.001):
     intersection = generate_ground_point(0.0, image_pt, camera)
     iterations = 0
     semi_major, semi_minor = get_radii(camera)
-    
+  
     source_proj = f'+proj=cart +a={semi_major} +b={semi_minor}'
     dest_proj = f'+proj=lonlat +a={semi_major} +b={semi_minor}'
     transformer = utils.create_transformer(source_proj, dest_proj)
-
     while iterations != max_its:
-        lon, lat, alt = transformer.transform(intersection.x, 
+        lon, lat, _ = transformer.transform(intersection.x, 
                                               intersection.y, 
                                               intersection.z,
                                               errcheck=True)
 
         px, py = dem.latlon_to_pixel(lat, lon)
         height = dem.read_array(1, [px, py, 1, 1])[0][0]
-
+        if height == dem.no_data_value:
+            raise ValueError(f'No DEM height at {lat}, {lon}')
+    
         next_intersection = camera.imageToGround(image_pt, float(height))
-        dist = max(abs(intersection.x - next_intersection.x),
-            abs(intersection.y - next_intersection.y),
-            abs(intersection.z - next_intersection.z))
+        dist = _compute_intersection_distance(intersection, next_intersection)
 
         intersection = next_intersection
         iterations += 1
@@ -182,6 +181,30 @@ def _(dem, image_pt, camera, max_its = 20, tolerance = 0.001):
             break
     return intersection
 
+def _compute_intersection_distance(intersection, next_intersection):
+    """
+    Private func that takes two csmapi Ecef objects or other objects with
+    x,y,z properties and computes the distance between them. This is the
+    maximum distance in 3D space.
+
+    Parameters
+    ----------
+    intersection : object
+                   Any object with x,y, and z properties that are numeric
+
+    next_intersection : object
+                        Any object with x,y, and z properties that are numeric              
+
+    Returns
+    -------
+    dist : float
+           The maximum distance between intersection and next_intersection
+           in one of the three planes (x,y,z)
+    """
+    return max(abs(intersection.x - next_intersection.x),
+            abs(intersection.y - next_intersection.y),
+            abs(intersection.z - next_intersection.z))
+
 def generate_boundary(isize, npoints=10):
     '''
     Generates a bounding box given a camera model
diff --git a/tests/test_csm.py b/tests/test_csm.py
new file mode 100644
index 0000000000000000000000000000000000000000..94fb524ec5daeb83b5b779625c31e40932892f3a
--- /dev/null
+++ b/tests/test_csm.py
@@ -0,0 +1,67 @@
+from unittest import mock
+import pytest
+
+from plio.io.io_gdal import GeoDataset
+
+import csmapi
+from knoten import csm
+
+@pytest.fixture
+def mock_dem():
+    mock_dem = mock.MagicMock(spec_set=GeoDataset)
+    mock_dem.no_data_value = 10
+    mock_dem.read_array.return_value = [[100]]
+    mock_dem.latlon_to_pixel.return_value = (0.5,0.5)
+    return mock_dem
+
+@pytest.fixture
+def mock_sensor():
+    mock_sensor = mock.MagicMock(spec=csmapi.RasterGM)
+    return mock_sensor
+
+@pytest.fixture
+def pt():
+    return csmapi.ImageCoord(0.0, 0.0)
+
+def test_generate_ground_point_with_float(mock_sensor):
+    csm.generate_ground_point(0, (0.5, 0.5), mock_sensor)
+    # The internal conversion from tuple to csmapi.ImageCoord means 
+    # assert_called_once_with fails due to different addresses of
+    # different objects.
+    mock_sensor.imageToGround.assert_called_once()
+
+def test_generate_ground_point_with_imagecoord(mock_sensor, pt):
+    height = 0.0
+    csm.generate_ground_point(height, pt, mock_sensor)
+    mock_sensor.imageToGround.assert_called_once_with(pt, height)
+
+@mock.patch.object(csm, 'get_radii', return_value=(10,10))
+@mock.patch.object(csm, '_compute_intersection_distance', return_value=0)
+@mock.patch('pyproj.transformer.Transformer.transform', return_value=(0,0,0))
+def test_generate_ground_point_with_dtm(mock_get_radii, 
+                                        mock_compute_intsesection, 
+                                        mock_pyproj_transformer, 
+                                        mock_sensor, pt, mock_dem):
+    csm.generate_ground_point(mock_dem, pt, mock_sensor)
+    # This call is mocked so that the intitial intersection and 
+    # one iteration should occur. Therefore, the call count
+    # should always be 2.
+    assert mock_sensor.imageToGround.call_count == 2
+
+from collections import namedtuple
+
+@mock.patch.object(csm, 'get_radii', return_value=(10,10))
+@mock.patch('pyproj.transformer.Transformer.transform', return_value=(0,0,0))
+def test_generate_ground_point_with_dtm_ndv(mock_get_radii,
+                                            mock_pyproj_transformer,
+                                            mock_sensor, pt, mock_dem):
+    mock_dem.no_data_value = 100
+    with pytest.raises(ValueError):
+        csm.generate_ground_point(mock_dem, pt, mock_sensor)
+
+def test__compute_intersection_distance():
+    Point = namedtuple("Point", 'x, y, z')
+    pt1 = Point(0,0,0)
+    pt2 = Point(1,1,1)
+    dist = csm._compute_intersection_distance(pt1, pt2)
+    assert dist == 1
\ No newline at end of file