diff --git a/src/main/java/org/orekit/rugged/api/Rugged.java b/src/main/java/org/orekit/rugged/api/Rugged.java
index fe9b8dcfd57fe264dc31e1f77f1dc400fe58ce97..b0d8c87663c696f60c1e4e74bcc9d7bcfa179143 100644
--- a/src/main/java/org/orekit/rugged/api/Rugged.java
+++ b/src/main/java/org/orekit/rugged/api/Rugged.java
@@ -27,6 +27,8 @@ import org.apache.commons.math3.util.FastMath;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.frames.Transform;
 import org.orekit.rugged.errors.DumpManager;
+import org.orekit.rugged.errors.InverseLocOutOfColumnRangeException;
+import org.orekit.rugged.errors.InverseLocOutOfLineRangeException;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.errors.RuggedMessages;
 import org.orekit.rugged.intersection.IntersectionAlgorithm;
@@ -376,25 +378,20 @@ public class Rugged {
      * @param minLine minimum line number
      * @param maxLine maximum line number
      * @return date at which ground point is seen by line sensor
+     * @exception InverseLocOutOfLineRangeException if the ground point is out of line range
      * @exception RuggedException if line cannot be localized, or sensor is unknown
      * @see #inverseLocation(String, GeodeticPoint, int, int)
      */
     public AbsoluteDate dateLocation(final String sensorName, final GeodeticPoint point,
                                      final int minLine, final int maxLine)
-        throws RuggedException {
+        throws InverseLocOutOfLineRangeException, RuggedException {
 
         final LineSensor sensor = getLineSensor(sensorName);
         final SensorMeanPlaneCrossing planeCrossing = getPlaneCrossing(sensorName, minLine, maxLine);
 
         // find approximately the sensor line at which ground point crosses sensor mean plane
         final Vector3D   target = ellipsoid.transform(point);
-        final SensorMeanPlaneCrossing.CrossingResult crossingResult = planeCrossing.find(target);
-        if (crossingResult == null) {
-            // target is out of search interval
-            return null;
-        } else {
-            return sensor.getDate(crossingResult.getLine());
-        }
+        return sensor.getDate(planeCrossing.find(target).getLine());
 
     }
 
@@ -408,14 +405,15 @@ public class Rugged {
      * @param longitude ground point longitude
      * @param minLine minimum line number
      * @param maxLine maximum line number
-     * @return sensor pixel seeing ground point, or null if ground point cannot
-     * be seen between the prescribed line numbers
+     * @return sensor pixel seeing ground point
+     * @exception InverseLocOutOfLineRangeException if the ground point is out of line range
+     * @exception InverseLocOutOfColumnRangeException if the ground point is out of column range
      * @exception RuggedException if line cannot be localized, or sensor is unknown
      */
     public SensorPixel inverseLocation(final String sensorName,
                                        final double latitude, final double longitude,
                                        final int minLine,  final int maxLine)
-        throws RuggedException {
+        throws InverseLocOutOfLineRangeException, InverseLocOutOfColumnRangeException, RuggedException {
         final GeodeticPoint groundPoint =
                 new GeodeticPoint(latitude, longitude, algorithm.getElevation(latitude, longitude));
         return inverseLocation(sensorName, groundPoint, minLine, maxLine);
@@ -426,72 +424,74 @@ public class Rugged {
      * @param point point to localize
      * @param minLine minimum line number
      * @param maxLine maximum line number
-     * @return sensor pixel seeing point, or null if point cannot be seen between the
-     * prescribed line numbers
+     * @return sensor pixel seeing point
+     * @exception InverseLocOutOfLineRangeException if the ground point is out of line range
+     * @exception InverseLocOutOfColumnRangeException if the ground point is out of column range
      * @exception RuggedException if line cannot be localized, or sensor is unknown
      * @see #dateLocation(String, GeodeticPoint, int, int)
      */
     public SensorPixel inverseLocation(final String sensorName, final GeodeticPoint point,
                                        final int minLine, final int maxLine)
-        throws RuggedException {
-
-        final LineSensor sensor = getLineSensor(sensorName);
-        DumpManager.dumpInverseLocation(sensor, point, minLine, maxLine,
-                                        lightTimeCorrection, aberrationOfLightCorrection);
-
-        final SensorMeanPlaneCrossing planeCrossing = getPlaneCrossing(sensorName, minLine, maxLine);
-
-        DumpManager.dumpSensorMeanPlane(planeCrossing);
-
-        // find approximately the sensor line at which ground point crosses sensor mean plane
-        final Vector3D   target = ellipsoid.transform(point);
-        final SensorMeanPlaneCrossing.CrossingResult crossingResult = planeCrossing.find(target);
-        if (crossingResult == null) {
-            // target is out of search interval
-            return null;
-        }
+        throws InverseLocOutOfLineRangeException, InverseLocOutOfColumnRangeException, RuggedException {
+
+        try {
+            final LineSensor sensor = getLineSensor(sensorName);
+            DumpManager.dumpInverseLocation(sensor, point, minLine, maxLine,
+                                            lightTimeCorrection, aberrationOfLightCorrection);
+
+            final SensorMeanPlaneCrossing planeCrossing = getPlaneCrossing(sensorName, minLine, maxLine);
+
+            DumpManager.dumpSensorMeanPlane(planeCrossing);
+
+            // find approximately the sensor line at which ground point crosses sensor mean plane
+            final Vector3D   target = ellipsoid.transform(point);
+            final SensorMeanPlaneCrossing.CrossingResult crossingResult = planeCrossing.find(target);
+
+            // find approximately the pixel along this sensor line
+            final SensorPixelCrossing pixelCrossing =
+                    new SensorPixelCrossing(sensor, planeCrossing.getMeanPlaneNormal(),
+                                            crossingResult.getTargetDirection().toVector3D(),
+                                            MAX_EVAL, COARSE_INVERSE_LOCATION_ACCURACY);
+            final double coarsePixel = pixelCrossing.locatePixel(crossingResult.getDate());
+            if (Double.isNaN(coarsePixel)) {
+                // target is out of search interval
+                return null;
+            }
 
-        // find approximately the pixel along this sensor line
-        final SensorPixelCrossing pixelCrossing =
-                new SensorPixelCrossing(sensor, planeCrossing.getMeanPlaneNormal(),
-                                        crossingResult.getTargetDirection().toVector3D(),
-                                        MAX_EVAL, COARSE_INVERSE_LOCATION_ACCURACY);
-        final double coarsePixel = pixelCrossing.locatePixel(crossingResult.getDate());
-        if (Double.isNaN(coarsePixel)) {
-            // target is out of search interval
-            return null;
+            // fix line by considering the closest pixel exact position and line-of-sight
+            // (this pixel might point towards a direction slightly above or below the mean sensor plane)
+            final int      lowIndex        = FastMath.max(0, FastMath.min(sensor.getNbPixels() - 2, (int) FastMath.floor(coarsePixel)));
+            final Vector3D lowLOS          = sensor.getLos(crossingResult.getDate(), lowIndex);
+            final Vector3D highLOS         = sensor.getLos(crossingResult.getDate(), lowIndex + 1);
+            final Vector3D localZ          = Vector3D.crossProduct(lowLOS, highLOS);
+            final DerivativeStructure beta = FieldVector3D.angle(crossingResult.getTargetDirection(), localZ);
+            final double   deltaL          = (0.5 * FastMath.PI - beta.getValue()) / beta.getPartialDerivative(1);
+            final double   fixedLine       = crossingResult.getLine() + deltaL;
+            final Vector3D fixedDirection  = new Vector3D(crossingResult.getTargetDirection().getX().taylor(deltaL),
+                                                          crossingResult.getTargetDirection().getY().taylor(deltaL),
+                                                          crossingResult.getTargetDirection().getZ().taylor(deltaL)).normalize();
+
+            // fix neighbouring pixels
+            final AbsoluteDate fixedDate   = sensor.getDate(fixedLine);
+            final Vector3D fixedX          = sensor.getLos(fixedDate, lowIndex);
+            final Vector3D fixedZ          = Vector3D.crossProduct(fixedX, sensor.getLos(fixedDate, lowIndex + 1));
+            final Vector3D fixedY          = Vector3D.crossProduct(fixedZ, fixedX);
+
+            // fix pixel
+            final double pixelWidth = FastMath.atan2(Vector3D.dotProduct(highLOS,        fixedY),
+                                                     Vector3D.dotProduct(highLOS,        fixedX));
+            final double alpha      = FastMath.atan2(Vector3D.dotProduct(fixedDirection, fixedY),
+                                                     Vector3D.dotProduct(fixedDirection, fixedX));
+            final double fixedPixel = lowIndex + alpha / pixelWidth;
+
+            final SensorPixel result = new SensorPixel(fixedLine, fixedPixel);
+            DumpManager.dumpInverseLocationResult(result);
+            return result;
+        } catch (RuggedException re) {
+            DumpManager.dumpException(re);
+            throw(re);
         }
 
-        // fix line by considering the closest pixel exact position and line-of-sight
-        // (this pixel might point towards a direction slightly above or below the mean sensor plane)
-        final int      lowIndex        = FastMath.max(0, FastMath.min(sensor.getNbPixels() - 2, (int) FastMath.floor(coarsePixel)));
-        final Vector3D lowLOS          = sensor.getLos(crossingResult.getDate(), lowIndex);
-        final Vector3D highLOS         = sensor.getLos(crossingResult.getDate(), lowIndex + 1);
-        final Vector3D localZ          = Vector3D.crossProduct(lowLOS, highLOS);
-        final DerivativeStructure beta = FieldVector3D.angle(crossingResult.getTargetDirection(), localZ);
-        final double   deltaL          = (0.5 * FastMath.PI - beta.getValue()) / beta.getPartialDerivative(1);
-        final double   fixedLine       = crossingResult.getLine() + deltaL;
-        final Vector3D fixedDirection  = new Vector3D(crossingResult.getTargetDirection().getX().taylor(deltaL),
-                                                      crossingResult.getTargetDirection().getY().taylor(deltaL),
-                                                      crossingResult.getTargetDirection().getZ().taylor(deltaL)).normalize();
-
-        // fix neighbouring pixels
-        final AbsoluteDate fixedDate   = sensor.getDate(fixedLine);
-        final Vector3D fixedX          = sensor.getLos(fixedDate, lowIndex);
-        final Vector3D fixedZ          = Vector3D.crossProduct(fixedX, sensor.getLos(fixedDate, lowIndex + 1));
-        final Vector3D fixedY          = Vector3D.crossProduct(fixedZ, fixedX);
-
-        // fix pixel
-        final double pixelWidth = FastMath.atan2(Vector3D.dotProduct(highLOS,        fixedY),
-                                                 Vector3D.dotProduct(highLOS,        fixedX));
-        final double alpha      = FastMath.atan2(Vector3D.dotProduct(fixedDirection, fixedY),
-                                                 Vector3D.dotProduct(fixedDirection, fixedX));
-        final double fixedPixel = lowIndex + alpha / pixelWidth;
-
-        final SensorPixel result = new SensorPixel(fixedLine, fixedPixel);
-        DumpManager.dumpInverseLocationResult(result);
-        return result;
-
     }
 
     /** Get the mean plane crossing finder for a sensor.
diff --git a/src/main/java/org/orekit/rugged/errors/Dump.java b/src/main/java/org/orekit/rugged/errors/Dump.java
index 3b581aa195b7bacad3a6254b2437e8fe01fefc41..c60c7374c60f6808a3bc1a57e24492181e261bc2 100644
--- a/src/main/java/org/orekit/rugged/errors/Dump.java
+++ b/src/main/java/org/orekit/rugged/errors/Dump.java
@@ -207,6 +207,19 @@ class Dump {
         }
     }
 
+    /** Dump an exception.
+     * @param e exception to dump
+     */
+    public void dumpException(final RuggedException e) {
+        writer.format(Locale.US,
+                      "Rugged exception: specifier %s parts",
+                      e.getSpecifier().toString());
+        for (final Object part : e.getParts()) {
+            writer.format(Locale.US, " %s", part);
+        }
+        writer.format(" %n");
+    }
+
     /** Dump an observation transform transform.
      * @param scToBody provider for observation
      * @param index index of the transform
diff --git a/src/main/java/org/orekit/rugged/errors/DumpManager.java b/src/main/java/org/orekit/rugged/errors/DumpManager.java
index 713beb5fe282d9596ae8c9d2b4163bb2f0b5d989..0dc11e0414cd6f82dd1ddecbc70cd396b86b0c43 100644
--- a/src/main/java/org/orekit/rugged/errors/DumpManager.java
+++ b/src/main/java/org/orekit/rugged/errors/DumpManager.java
@@ -186,6 +186,15 @@ public class DumpManager {
         }
     }
 
+    /** Dump an exception.
+     * @param e exception to dump
+     */
+    public static void dumpException(final RuggedException e) {
+        if (isActive()) {
+            DUMP.get().dumpException(e);
+        }
+    }
+
     /** Dump an observation transform transform.
      * @param scToBody provider for observation
      * @param index index of the transform
diff --git a/src/main/java/org/orekit/rugged/errors/DumpReplayer.java b/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
index 6fdec2250b694f0c80b56512c54595f16a71b062..4f5f8c006051da8152b16dc608ca3f4aa97b25c4 100644
--- a/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
+++ b/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
@@ -34,6 +34,7 @@ import java.util.NavigableMap;
 import java.util.TreeMap;
 
 import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
+import org.apache.commons.math3.exception.util.Localizable;
 import org.apache.commons.math3.exception.util.LocalizedFormats;
 import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
 import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
@@ -44,6 +45,7 @@ import org.apache.commons.math3.util.Pair;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.bodies.OneAxisEllipsoid;
 import org.orekit.errors.OrekitException;
+import org.orekit.errors.OrekitMessages;
 import org.orekit.frames.Frame;
 import org.orekit.frames.FramesFactory;
 import org.orekit.frames.Predefined;
@@ -211,6 +213,12 @@ public class DumpReplayer {
     /** Keyword for target direction. */
     private static final String TARGET_DIRECTION = "targetDirection";
 
+    /** Keyword for exception specifier. */
+    private static final String SPECIFIER = "specifier";
+
+    /** Keyword for exception parts. */
+    private static final String PARTS = "parts";
+
     /** Constant elevation for constant elevation algorithm. */
     private double constantElevation;
 
@@ -436,8 +444,13 @@ public class DumpReplayer {
     public Result[] execute(final Rugged rugged) throws RuggedException {
         final Result[] results = new Result[calls.size()];
         for (int i = 0; i < calls.size(); ++i) {
-            results[i] = new Result(calls.get(i).expected,
-                                    calls.get(i).execute(rugged));
+            Object result = null;
+            try {
+                result = calls.get(i).execute(rugged);
+            } catch (RuggedException re) {
+                result = re;
+            }
+            results[i] = new Result(calls.get(i).expected, result);
         }
         return results;
     }
@@ -963,6 +976,35 @@ public class DumpReplayer {
 
             }
 
+        },
+
+        /** Parser for exception dump lines. */
+        RUGGED_EXCEPTION() {
+
+            /** {@inheritDoc} */
+            @Override
+            public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global)
+                throws RuggedException {
+                if (fields.length < 3 || !fields[0].equals(SPECIFIER) || !fields[2].equals(PARTS)) {
+                    throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
+                }
+                Localizable specifier = null;
+                try {
+                    specifier = RuggedMessages.valueOf(fields[1]);
+                } catch (IllegalArgumentException e1) {
+                    try {
+                        specifier = OrekitMessages.valueOf(fields[1]);
+                    } catch (IllegalArgumentException e2) {
+                        specifier = LocalizedFormats.valueOf(fields[1]);
+                    }
+                }
+                final Object[] parts = new Object[fields.length -  3];
+                System.arraycopy(fields, 3, parts, 0, parts.length);
+                final RuggedException re = new RuggedException(specifier, parts);
+                final DumpedCall last = global.calls.get(global.calls.size() - 1);
+                last.expected = re;
+            }
+
         };
 
         /** Parse a line.
diff --git a/src/main/java/org/orekit/rugged/errors/InverseLocOutOfColumnRangeException.java b/src/main/java/org/orekit/rugged/errors/InverseLocOutOfColumnRangeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6fad86501e5bdc1b0500a04030a129661b38679
--- /dev/null
+++ b/src/main/java/org/orekit/rugged/errors/InverseLocOutOfColumnRangeException.java
@@ -0,0 +1,45 @@
+/* Copyright 2013-2015 CS Systèmes d'Information
+ * Licensed to CS Systèmes d'Information (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.orekit.rugged.errors;
+
+
+/** This class is a specialized exception for inverse location errors.
+ * @author Luc Maisonobe
+ */
+
+public class InverseLocOutOfColumnRangeException extends RuggedException {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 20150518L;
+
+    /** Simple constructor.
+     * @param expectedColumn expected column number for the ground point
+     * @param minColumn minimum column number
+     * @param maxColumn maximum column number
+     */
+    public InverseLocOutOfColumnRangeException(final double expectedColumn, final int minColumn, final int maxColumn) {
+        super(RuggedMessages.GROUND_POINT_OUT_OF_COLUMN_RANGE, expectedColumn, minColumn, maxColumn);
+    }
+
+    /** Get the expected column number for the ground point.
+     * @return expected column number for the ground point
+     */
+    public double getExpectedColumn() {
+        return ((Double) getParts()[0]).doubleValue();
+    }
+
+}
diff --git a/src/main/java/org/orekit/rugged/errors/InverseLocOutOfLineRangeException.java b/src/main/java/org/orekit/rugged/errors/InverseLocOutOfLineRangeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..833e09a8bd7b0ec21ea526cdc131674f9ee85919
--- /dev/null
+++ b/src/main/java/org/orekit/rugged/errors/InverseLocOutOfLineRangeException.java
@@ -0,0 +1,45 @@
+/* Copyright 2013-2015 CS Systèmes d'Information
+ * Licensed to CS Systèmes d'Information (CS) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * CS licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.orekit.rugged.errors;
+
+
+/** This class is a specialized exception for inverse location errors.
+ * @author Luc Maisonobe
+ */
+
+public class InverseLocOutOfLineRangeException extends RuggedException {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 20150518L;
+
+    /** Simple constructor.
+     * @param expectedLine expected line number for the ground point
+     * @param minLine minimum line number
+     * @param maxLine maximum line number
+     */
+    public InverseLocOutOfLineRangeException(final double expectedLine, final int minLine, final int maxLine) {
+        super(RuggedMessages.GROUND_POINT_OUT_OF_LINE_RANGE, expectedLine, minLine, maxLine);
+    }
+
+    /** Get the expected line number for the ground point.
+     * @return expected line number for the ground point
+     */
+    public double getExpectedLine() {
+        return ((Double) getParts()[0]).doubleValue();
+    }
+
+}
diff --git a/src/main/java/org/orekit/rugged/errors/RuggedMessages.java b/src/main/java/org/orekit/rugged/errors/RuggedMessages.java
index e657479f34b7395dac153d422e033f6ef1eb2356..f3cb9741edba402fc7b4ee51d1db95f5d2d6e8b0 100644
--- a/src/main/java/org/orekit/rugged/errors/RuggedMessages.java
+++ b/src/main/java/org/orekit/rugged/errors/RuggedMessages.java
@@ -63,6 +63,8 @@ public enum RuggedMessages implements Localizable {
     LINE_OF_SIGHT_NEVER_CROSSES_LATITUDE("line-of-sight never crosses latitude {0}"),
     LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE("line-of-sight never crosses longitude {0}"),
     LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE("line-of-sight never crosses altitude {0}"),
+    GROUND_POINT_OUT_OF_LINE_RANGE("ground point is around line {0}, out of the [{1}, {2}] range"),
+    GROUND_POINT_OUT_OF_COLUMN_RANGE("ground point is around column {0}, out of the [{1}, {2}] range"),
     DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT("line-of-sight enters the Digital Elevation Model behind spacecraft!"),
     FRAMES_MISMATCH_WITH_INTERPOLATOR_DUMP("frame {0} does not match frame {1} from interpolator dump"),
     NOT_INTERPOLATOR_DUMP_DATA("data is not an interpolator dump"),
diff --git a/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java b/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
index 4f7bcce0a5928deda893a0043d0a71df774a52f9..5ca1b0cbac87cdeef149bbc9995c2dd13c6bddae 100644
--- a/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
+++ b/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
@@ -21,6 +21,7 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
 import org.apache.commons.math3.analysis.solvers.BracketingNthOrderBrentSolver;
 import org.apache.commons.math3.analysis.solvers.UnivariateSolver;
 import org.apache.commons.math3.exception.NoBracketingException;
+import org.apache.commons.math3.exception.util.LocalizedFormats;
 import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math3.linear.Array2DRowRealMatrix;
@@ -35,6 +36,7 @@ import org.apache.commons.math3.linear.SingularValueDecomposition;
 import org.apache.commons.math3.util.FastMath;
 import org.apache.commons.math3.util.Precision;
 import org.orekit.frames.Transform;
+import org.orekit.rugged.errors.InverseLocOutOfLineRangeException;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.errors.RuggedExceptionWrapper;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
@@ -331,13 +333,13 @@ public class SensorMeanPlaneCrossing {
 
     /** Find mean plane crossing.
      * @param target target ground point
-     * @return line number and target direction at mean plane crossing,
-     * or null if search interval does not bracket a solution
+     * @return line number and target direction at mean plane crossing
+     * @exception InverseLocOutOfLineRangeException if the ground point is out of line range
      * @exception RuggedException if geometry cannot be computed for some line or
      * if the maximum number of evaluations is exceeded
      */
     public CrossingResult find(final Vector3D target)
-        throws RuggedException {
+        throws InverseLocOutOfLineRangeException, RuggedException {
 
         double crossingLine     = midLine;
         Transform bodyToInert   = midBodyToInert;
@@ -410,9 +412,6 @@ public class SensorMeanPlaneCrossing {
                     // rare case: we are stuck in a loop!
                     // switch to a more robust (but slower) algorithm in this case
                     final CrossingResult slowResult = slowFind(targetPV, crossingLine);
-                    if (slowResult == null) {
-                        return null;
-                    }
                     for (int k = cachedResults.length - 1; k > 0; --k) {
                         cachedResults[k] = cachedResults[k - 1];
                     }
@@ -425,7 +424,7 @@ public class SensorMeanPlaneCrossing {
                 if (atMin) {
                     // we were already trying at minLine and we need to go below that
                     // give up as the solution is out of search interval
-                    return null;
+                    throw new InverseLocOutOfLineRangeException(crossingLine, minLine, maxLine);
                 }
                 atMin        = true;
                 crossingLine = minLine;
@@ -433,7 +432,7 @@ public class SensorMeanPlaneCrossing {
                 if (atMax) {
                     // we were already trying at maxLine and we need to go above that
                     // give up as the solution is out of search interval
-                    return null;
+                    throw new InverseLocOutOfLineRangeException(crossingLine, minLine, maxLine);
                 }
                 atMax        = true;
                 crossingLine = maxLine;
@@ -448,7 +447,7 @@ public class SensorMeanPlaneCrossing {
             scToInert   = scToBody.getScToInertial(date);
         }
 
-        return null;
+        throw new RuggedException(LocalizedFormats.MAX_COUNT_EXCEEDED, maxEval);
 
     }
 
@@ -496,6 +495,24 @@ public class SensorMeanPlaneCrossing {
      */
     public CrossingResult slowFind(final PVCoordinates targetPV, final double initialGuess)
         throws RuggedException {
+
+        // set up function evaluating to 0.0 where target matches line
+        final UnivariateFunction f = new UnivariateFunction() {
+            /** {@inheritDoc} */
+            @Override
+            public double value(final double x) throws RuggedExceptionWrapper {
+                try {
+                    final AbsoluteDate date = sensor.getDate(x);
+                    final FieldVector3D<DerivativeStructure> targetDirection =
+                            evaluateLine(x, targetPV, scToBody.getBodyToInertial(date), scToBody.getScToInertial(date));
+                    final DerivativeStructure beta = FieldVector3D.angle(targetDirection, meanPlaneNormal);
+                    return 0.5 * FastMath.PI - beta.getValue();
+                } catch (RuggedException re) {
+                    throw new RuggedExceptionWrapper(re);
+                }
+            }
+        };
+
         try {
 
             // safety check
@@ -507,21 +524,7 @@ public class SensorMeanPlaneCrossing {
             }
 
             final UnivariateSolver solver = new BracketingNthOrderBrentSolver(accuracy, 5);
-            double crossingLine = solver.solve(maxEval, new UnivariateFunction() {
-                /** {@inheritDoc} */
-                @Override
-                public double value(final double x) throws RuggedExceptionWrapper {
-                    try {
-                        final AbsoluteDate date = sensor.getDate(x);
-                        final FieldVector3D<DerivativeStructure> targetDirection =
-                                evaluateLine(x, targetPV, scToBody.getBodyToInertial(date), scToBody.getScToInertial(date));
-                        final DerivativeStructure beta = FieldVector3D.angle(targetDirection, meanPlaneNormal);
-                        return 0.5 * FastMath.PI - beta.getValue();
-                    } catch (RuggedException re) {
-                        throw new RuggedExceptionWrapper(re);
-                    }
-                }
-            }, minLine, maxLine, startValue);
+            double crossingLine = solver.solve(maxEval, f, minLine, maxLine, startValue);
 
             final AbsoluteDate date = sensor.getDate(crossingLine);
             final FieldVector3D<DerivativeStructure> targetDirection =
@@ -529,10 +532,14 @@ public class SensorMeanPlaneCrossing {
             return new CrossingResult(sensor.getDate(crossingLine), crossingLine, targetPV.getPosition(), targetDirection);
 
         } catch (NoBracketingException nbe) {
-            return null;
+            final double fMinLine     = f.value(minLine);
+            final double fMaxLine     = f.value(maxLine);
+            final double expectedLine = (fMaxLine * minLine - fMinLine * maxLine) / (fMaxLine - fMinLine);
+            throw new InverseLocOutOfLineRangeException(expectedLine, minLine, maxLine);
         } catch (RuggedExceptionWrapper rew) {
             throw rew.getException();
         }
+
     }
 
     /** Evaluate geometry for a given line number.
diff --git a/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java b/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java
index 0e972175d6a342c1d7aceed783217a5823df741f..d3e04c8ed54ba7850360c86deedfc55f9cb556f6 100644
--- a/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java
+++ b/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java
@@ -23,6 +23,7 @@ import org.apache.commons.math3.exception.NoBracketingException;
 import org.apache.commons.math3.exception.TooManyEvaluationsException;
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math3.util.FastMath;
+import org.orekit.rugged.errors.InverseLocOutOfColumnRangeException;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.errors.RuggedExceptionWrapper;
 import org.orekit.time.AbsoluteDate;
@@ -68,25 +69,27 @@ public class SensorPixelCrossing {
 
     /** Locate pixel along sensor line.
      * @param date current date
-     * @return pixel location ({@code Double.NaN} if the first and last
-     * pixels of the line do not bracket a location)
+     * @return pixel location
+     * @exception InverseLocOutOfColumnRangeException if the ground point is out of column range
      * @exception RuggedException if the maximum number of evaluations is exceeded
      */
-    public double locatePixel(final AbsoluteDate date) throws RuggedException {
-        try {
-
-            // set up function evaluating to 0.0 where target matches pixel
-            final UnivariateFunction f = new UnivariateFunction() {
-                /** {@inheritDoc} */
-                @Override
-                public double value(final double x) throws RuggedExceptionWrapper {
-                    try {
-                        return Vector3D.angle(cross, getLOS(date, x)) - 0.5 * FastMath.PI;
-                    } catch (RuggedException re) {
-                        throw new RuggedExceptionWrapper(re);
-                    }
+    public double locatePixel(final AbsoluteDate date)
+        throws InverseLocOutOfColumnRangeException, RuggedException {
+
+        // set up function evaluating to 0.0 where target matches pixel
+        final UnivariateFunction f = new UnivariateFunction() {
+            /** {@inheritDoc} */
+            @Override
+            public double value(final double x) throws RuggedExceptionWrapper {
+                try {
+                    return Vector3D.angle(cross, getLOS(date, x)) - 0.5 * FastMath.PI;
+                } catch (RuggedException re) {
+                    throw new RuggedExceptionWrapper(re);
                 }
-            };
+            }
+        };
+
+        try {
 
             // find the root
             final UnivariateSolver solver =
@@ -94,8 +97,12 @@ public class SensorPixelCrossing {
             return solver.solve(maxEval, f, -MARGIN, sensor.getNbPixels() - 1 + MARGIN);
 
         } catch (NoBracketingException nbe) {
-            // there are no solutions in the search interval
-            return Double.NaN;
+            final int minPixel         = 0;
+            final int maxPixel         = sensor.getNbPixels() - 1;
+            final double fMinPixel     = f.value(minPixel);
+            final double fMaxPixel     = f.value(maxPixel);
+            final double expectedPixel = (fMaxPixel * minPixel - fMinPixel * maxPixel) / (fMaxPixel - fMinPixel);
+            throw new InverseLocOutOfColumnRangeException(expectedPixel, minPixel, maxPixel);
         } catch (TooManyEvaluationsException tmee) {
             throw new RuggedException(tmee);
         } catch (RuggedExceptionWrapper rew) {
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8
index c65fd1b2371f9235c7f658925aa77bcfb9f6647e..13a0465aeac7447f93a5debb04e4dcfaa2eaf6b2 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_de.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = die Sichtverbindung kreuzt nie die Läng
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = die Linie kreuzt nie die Höhe {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = <MISSING TRANSLATION>
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = <MISSING TRANSLATION>
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = die Sichtverbindung tritt in das digitale Höhenlinienmodell ein, hinter dem Satellite!
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8
index 7d5f68fab8a4151c3b88367ce7b60d238eb458aa..63908662cc821dca65bfca52010e4c255b1e02d9 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_en.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = line-of-sight never crosses longitude {0
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = line-of-sight never crosses altitude {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = ground point is around line {0}, out of the [{1}, {2}] range
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = ground point is around column {0}, out of the [{1}, {2}] range
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = line-of-sight enters the Digital Elevation Model behind spacecraft!
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8
index 44b538430d2af4605ef34c71863208528ac7bc29..8490d5b7a8eeb727180c560f9589f434ad134abe 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_es.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = la línea de visión nunca atraviesa la
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = la línea de visión nunca atraviesa la altitud {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = <MISSING TRANSLATION>
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = <MISSING TRANSLATION>
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = ¡ la línea de visión entra en el Modelo Digital del Terreno por detrás del satélite !
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8
index b3e5c040e8f8c48a3cb89439fb85ed967c40dd1f..94d159f71596e029cfb50b0160df869fa855c577 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_fr.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = la ligne de visée ne franchit jamais la
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = la ligne de visée ne franchit jamais l''altitude {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = le point au sol est aux alentours de la ligne {0}, hors du domaine [{1}, {2}]
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = le point au sol est aux alentours de la colonne {0}, hors du domaine [{1}, {2}]
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = la ligne de visée entre dans le Modèle Numérique de Terrain derrière le satellite !
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8
index b927d20a22e3eaaf5541199a0b1c9b75fd0e1d6e..bb21a777bce1c2c5f0fed8563e03c9e391992712 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_gl.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = a liña de visión xamais atravesa a lon
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = a liña de visión xamais atravesa a altitude {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = <MISSING TRANSLATION>
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = <MISSING TRANSLATION>
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = ¡ a liña de visión entra no Modelo Dixital do Terren por detrás do satélite !
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8
index 35ae33430a3d11cecff9c95c44374ae535c8c302..12b41ac26e596c27b5c0025886483cf4844ed8ac 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_it.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = la linea di visibilità non attraversa m
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = la linea di visibilità non attraversa mai la altitudine {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = <MISSING TRANSLATION>
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = <MISSING TRANSLATION>
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = la linea di visibilità entra nel Modello Digitale di Suolo dietro il satellite!
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_no.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_no.utf8
index 90280718842ca66ec803b808c3786fa2b2293f4e..db88653aca8a3f489cc0bbe593850073e3caac69 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_no.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_no.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = synslinjen krysser aldri lengdegrad {0}
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = linjen krysser aldri høyden {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = <MISSING TRANSLATION>
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = <MISSING TRANSLATION>
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = synslinjen går inn i den digital terrengmodellen bak romfartøyet
 
diff --git a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_ro.utf8 b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_ro.utf8
index 900187a721af177d906e4c800cb9b2fa15a4ba76..0dff443c53e508704894aee28811872332e9168a 100644
--- a/src/main/resources/assets/org/orekit/rugged/RuggedMessages_ro.utf8
+++ b/src/main/resources/assets/org/orekit/rugged/RuggedMessages_ro.utf8
@@ -37,6 +37,12 @@ LINE_OF_SIGHT_NEVER_CROSSES_LONGITUDE = linia de vizare nu intersectează longit
 # line never crosses altitude {0}
 LINE_OF_SIGHT_NEVER_CROSSES_ALTITUDE = linia de vizare nu intersectează altitudinea {0}
 
+# ground point is around line {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_LINE_RANGE = <MISSING TRANSLATION>
+
+# ground point is around column {0}, out of the [{1}, {2}] range
+GROUND_POINT_OUT_OF_COLUMN_RANGE = <MISSING TRANSLATION>
+
 # line-of-sight enters the Digital Elevation Model behind spacecraft!
 DEM_ENTRY_POINT_IS_BEHIND_SPACECRAFT = linia de vizare intră în Modelul Digital de Elevație în spatele navei spațiale!
 
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 8f9d7f4595a5a8b1de8d019055f51b87e64934ee..81c2eb357d8cf0ba8845cba458d0d5adc46c578c 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -22,6 +22,11 @@
   <body>
     <release version="1.0" date="TBD"
              description="TBD">
+      <action dev="luc" type="update" >
+        Use specific exceptions rather than returning null when inverse location identifies
+        out of range errors along lines or columns. This helps caller to set fix the
+        min/max lines as we can provide information about where the point is expected.
+      </action>
       <action dev="luc" type="add" >
         Added a CONSTANT_ELEVATION_OVER_ELLIPSOID algorithm, similar in spirit
         to the IGNORE_DEM_USE_ELLIPSOID, but with a user-specified elevation
diff --git a/src/test/java/org/orekit/rugged/api/RuggedTest.java b/src/test/java/org/orekit/rugged/api/RuggedTest.java
index 00252890401605ca4dee585734ea44c9d7c237e5..b82e23109afbe6541bdc98047d3027db899e80f4 100644
--- a/src/test/java/org/orekit/rugged/api/RuggedTest.java
+++ b/src/test/java/org/orekit/rugged/api/RuggedTest.java
@@ -48,6 +48,8 @@ import org.orekit.frames.FramesFactory;
 import org.orekit.orbits.Orbit;
 import org.orekit.propagation.Propagator;
 import org.orekit.rugged.TestUtils;
+import org.orekit.rugged.errors.InverseLocOutOfColumnRangeException;
+import org.orekit.rugged.errors.InverseLocOutOfLineRangeException;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.errors.RuggedMessages;
 import org.orekit.rugged.linesensor.LineDatation;
@@ -990,32 +992,52 @@ public class RuggedTest {
         }
 
         // point out of line (20 pixels before first pixel)
-        Assert.assertNull(rugged.inverseLocation("line",
+        try {
+            rugged.inverseLocation("line",
                                                     21 * gp[0].getLatitude()  - 20 * gp[1].getLatitude(),
                                                     21 * gp[0].getLongitude() - 20 * gp[1].getLongitude(),
-                                                    0, dimension));
+                                                    0, dimension);
+            Assert.fail("an exception should have been thrown");
+        } catch (InverseLocOutOfColumnRangeException e) {
+            Assert.assertEquals(-20, e.getExpectedColumn(), 1.0);
+        }
 
         // point out of line (20 pixels after last pixel)
-        Assert.assertNull(rugged.inverseLocation("line",
-                                                    -20 * gp[gp.length - 2].getLatitude()  + 21 * gp[gp.length - 1].getLatitude(),
-                                                    -20 * gp[gp.length - 2].getLongitude() + 21 * gp[gp.length - 1].getLongitude(),
-                                                    0, dimension));
+        try {
+            rugged.inverseLocation("line",
+                                   -20 * gp[gp.length - 2].getLatitude()  + 21 * gp[gp.length - 1].getLatitude(),
+                                   -20 * gp[gp.length - 2].getLongitude() + 21 * gp[gp.length - 1].getLongitude(),
+                                   0, dimension);
+            Assert.fail("an exception should have been thrown");
+        } catch (InverseLocOutOfColumnRangeException e) {
+            Assert.assertEquals(2019.0, e.getExpectedColumn(), 1.0);
+        }
 
         // point out of line (20 lines before first line)
         GeodeticPoint[] gp0 = rugged.directLocation("line", 0);
         GeodeticPoint[] gp1 = rugged.directLocation("line", 1);
-        Assert.assertNull(rugged.inverseLocation("line",
-                                                    21 * gp0[dimension / 2].getLatitude()  - 20 * gp1[dimension / 2].getLatitude(),
-                                                    21 * gp0[dimension / 2].getLongitude() - 20 * gp1[dimension / 2].getLongitude(),
-                                                    0, dimension));
+        try {
+            rugged.inverseLocation("line",
+                                   21 * gp0[dimension / 2].getLatitude()  - 20 * gp1[dimension / 2].getLatitude(),
+                                   21 * gp0[dimension / 2].getLongitude() - 20 * gp1[dimension / 2].getLongitude(),
+                                   0, dimension);
+            Assert.fail("an exception should have been thrown");
+        } catch (InverseLocOutOfLineRangeException e) {
+            Assert.assertEquals(-20, e.getExpectedLine(), 1.0);
+        }
 
         // point out of line (20 lines after last line)
         GeodeticPoint[] gp2 = rugged.directLocation("line", dimension - 2);
         GeodeticPoint[] gp3 = rugged.directLocation("line", dimension - 1);
-        Assert.assertNull(rugged.inverseLocation("line",
-                                                    -20 * gp2[dimension / 2].getLatitude()  + 21 * gp3[dimension / 2].getLatitude(),
-                                                    -20 * gp2[dimension / 2].getLongitude() + 21 * gp3[dimension / 2].getLongitude(),
-                                                    0, dimension));
+        try {
+            rugged.inverseLocation("line",
+                                   -20 * gp2[dimension / 2].getLatitude()  + 21 * gp3[dimension / 2].getLatitude(),
+                                   -20 * gp2[dimension / 2].getLongitude() + 21 * gp3[dimension / 2].getLongitude(),
+                                   0, dimension);
+            Assert.fail("an exception should have been thrown");
+        } catch (InverseLocOutOfLineRangeException e) {
+            Assert.assertEquals(2019.0, e.getExpectedLine(), 1.0);
+        }
 
     }
 
@@ -1082,18 +1104,28 @@ public class RuggedTest {
         // point out of line (20 lines before first line)
         GeodeticPoint[] gp0 = rugged.directLocation("line", 0);
         GeodeticPoint[] gp1 = rugged.directLocation("line", 1);
-        Assert.assertNull(rugged.dateLocation("line",
-                                                    21 * gp0[dimension / 2].getLatitude()  - 20 * gp1[dimension / 2].getLatitude(),
-                                                    21 * gp0[dimension / 2].getLongitude() - 20 * gp1[dimension / 2].getLongitude(),
-                                                    0, dimension));
+        try {
+            rugged.dateLocation("line",
+                                21 * gp0[dimension / 2].getLatitude()  - 20 * gp1[dimension / 2].getLatitude(),
+                                21 * gp0[dimension / 2].getLongitude() - 20 * gp1[dimension / 2].getLongitude(),
+                                0, dimension);
+            Assert.fail("an exception should have been thrown");
+        } catch (InverseLocOutOfLineRangeException e) {
+            Assert.assertEquals(-20.0, e.getExpectedLine(), 1.0);
+        }
 
         // point out of line (20 lines after last line)
         GeodeticPoint[] gp2 = rugged.directLocation("line", dimension - 2);
         GeodeticPoint[] gp3 = rugged.directLocation("line", dimension - 1);
-        Assert.assertNull(rugged.dateLocation("line",
-                                                    -20 * gp2[dimension / 2].getLatitude()  + 21 * gp3[dimension / 2].getLatitude(),
-                                                    -20 * gp2[dimension / 2].getLongitude() + 21 * gp3[dimension / 2].getLongitude(),
-                                                    0, dimension));
+        try {
+            rugged.dateLocation("line",
+                                -20 * gp2[dimension / 2].getLatitude()  + 21 * gp3[dimension / 2].getLatitude(),
+                                -20 * gp2[dimension / 2].getLongitude() + 21 * gp3[dimension / 2].getLongitude(),
+                                0, dimension);
+            Assert.fail("an exception should have been thrown");
+        } catch (InverseLocOutOfLineRangeException e) {
+            Assert.assertEquals(2019.0, e.getExpectedLine(), 1.0);
+        }
 
     }
 
diff --git a/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java b/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java
index 572a74f2753081eb01bf8d866b4fc76e7ca293d7..b4fa3fa0e4a6df6b35e1ec2ce224565793ded921 100644
--- a/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java
+++ b/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java
@@ -123,4 +123,29 @@ public class DumpReplayerTest {
 
     }
 
+    @Test
+    public void testInverseLoc03() throws URISyntaxException, IOException, OrekitException, RuggedException {
+
+        String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
+        DataProvidersManager.getInstance().addProvider(new DirectoryCrawler(new File(orekitPath)));
+
+        String dumpPath = getClass().getClassLoader().getResource("replay/replay-inverse-loc-03.txt").toURI().getPath();
+        DumpReplayer replayer = new DumpReplayer();
+        replayer.parse(new File(dumpPath));
+        Rugged rugged = replayer.createRugged();
+        DumpReplayer.Result[] results = replayer.execute(rugged);
+
+        Assert.assertEquals(1, results.length);
+        for (final DumpReplayer.Result result : results) {
+            RuggedException expectedSP = (RuggedException) result.getExpected();
+            RuggedException replayedSP = (RuggedException) result.getReplayed();
+            Assert.assertEquals(expectedSP.getSpecifier(), replayedSP.getSpecifier());
+            Assert.assertEquals(expectedSP.getParts().length, replayedSP.getParts().length);
+            for (int i = 0; i < expectedSP.getParts().length; ++i) {
+                Assert.assertEquals(expectedSP.getParts()[i].toString(), replayedSP.getParts()[i].toString());
+            }
+        }
+
+    }
+
 }
diff --git a/src/test/java/org/orekit/rugged/errors/RuggedMessagesTest.java b/src/test/java/org/orekit/rugged/errors/RuggedMessagesTest.java
index fa07bcf5d9d120436e25b35bfa860c8844e95ad4..90afd4c38e7a0cc77c73f1e88ed0e1b807bcbfca 100644
--- a/src/test/java/org/orekit/rugged/errors/RuggedMessagesTest.java
+++ b/src/test/java/org/orekit/rugged/errors/RuggedMessagesTest.java
@@ -30,7 +30,7 @@ public class RuggedMessagesTest {
 
     @Test
     public void testMessageNumber() {
-        Assert.assertEquals(25, RuggedMessages.values().length);
+        Assert.assertEquals(27, RuggedMessages.values().length);
     }
 
     @Test
diff --git a/src/test/resources/replay/replay-inverse-loc-03.txt b/src/test/resources/replay/replay-inverse-loc-03.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d02d1a4764b52ab180955861d7a1ec2bcca25b19
--- /dev/null
+++ b/src/test/resources/replay/replay-inverse-loc-03.txt
@@ -0,0 +1,15 @@
+# Rugged library dump file, created on 2015-05-13T10:02:15Z
+# all units are SI units (m, m/s, rad ...)
+sensor: sensorName s0 nbPixels 2548 position  0.000000000000000e+00 0.000000000000000e+00  0.000000000000000e+00
+sensor datation: sensorName s0 lineNumber  2.534400000000000e+05 date 2009-12-11T10:56:08.87816069400002Z
+sensor datation: sensorName s0 lineNumber  3.456000000000000e+05 date 2009-12-11T10:58:33.19814021399996Z
+inverse location: sensorName s0 latitude  8.744540902932477e-01 longitude  8.223965816103829e-02 elevation  1.932387539216973e+02 minLine 253440 maxLine 345600 lightTime false aberration false
+sensor mean plane: sensorName s0 minLine 253440 maxLine 345600 maxEval 50 accuracy  1.000000000000000e-02 normal 9.992992685324403e-01  3.581342262283560e-02  1.087982860931817e-02 cachedResults 0
+sensor datation: sensorName s0 lineNumber  2.995200000000000e+05 date 2009-12-11T10:57:21.03815045399999Z
+span: minDate 2009-12-11T10:49:31.00000000000000Z maxDate 2009-12-11T11:03:30.00000000000000Z tStep  1.000000000000000e-01 tolerance  1.000000000000000e+01 inertialFrame EME2000
+transform: index 4700 body r  5.336117270046078e-01 4.251589590898946e-04 -2.597710250850116e-04  8.457294346078028e-01 Ω -7.257892947630780e-08 -1.030887896243645e-09 -7.292111453494791e-05 ΩDot -1.960038458846624e-16 2.118427550826115e-16  1.921009249184302e-19 spacecraft p -2.053168038837612e-01 -4.479465554468334e-01 -7.157555881515884e+06 v -6.899290198987784e-02 -3.025941225892836e-02 -5.079406124814291e+00 a  3.805095952731160e-01 5.497720860602762e-01 -8.918837042129590e-03 r -2.219560290614089e-01 -4.227878241169732e-01 8.530519262360150e-01  2.104480650582249e-01 Ω -8.821450598425838e-04  5.190249503929784e-04  2.032835938889824e-04 ΩDot -4.852855703503804e-08 -1.727683064915104e-07 -5.843961481065110e-09
+ellipsoid: ae  6.378137000000000e+06 f  3.352810664747481e-03 frame ITRF_CIO_CONV_2010_SIMPLE_EOP
+sensor rate: sensorName s0 lineNumber  2.995200000000000e+05 rate 6.385810218828944e+02
+transform: index 5422 body r  5.358362189638148e-01 4.244746734277517e-04 -2.608866680050883e-04  8.443217977797100e-01 Ω -7.257894362971709e-08 -1.030872599745237e-09 -7.292111453507905e-05 ΩDot -1.960533569532405e-16 2.118830189595701e-16  1.921497489163665e-19 spacecraft p -2.077100353781134e-01 -5.937387477606535e-01 -7.157941245109990e+06 v -2.079879880167868e-02  6.790481151207040e-02 -5.590344257542220e+00 a  2.559067822717660e-01 1.523619888721470e+00 -6.690495582427680e-03 r -2.527575739550456e-01 -4.131723819265151e-01 8.446513348497744e-01  2.279612119594559e-01 Ω -8.835025599828953e-04  5.181159787201125e-04  1.981184601497435e-04 ΩDot -4.833822353095120e-08 -2.339809966148790e-08 -3.757527734431237e-07
+sensor rate: sensorName s0 lineNumber  3.456000000000000e+05 rate 6.385810218828944e+02
+Rugged exception: specifier GROUND_POINT_OUT_OF_LINE_RANGE parts 345933.8595532291 253440 345600