Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java	(revision 19226)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java	(revision 19227)
@@ -13,4 +13,5 @@
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -18,4 +19,5 @@
 import java.util.EnumSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -287,5 +289,7 @@
         // Since the created way is left selected, we need to unselect again here
         if (pWays != null && pWays.getWays() != null) {
-            getLayerManager().getEditDataSet().clearSelection(pWays.getWays());
+            final List<Way> ways = new ArrayList<>(pWays.getWays());
+            ways.removeIf(w -> w.getDataSet() == null);
+            getLayerManager().getEditDataSet().clearSelection(ways);
             pWays = null;
         }
Index: trunk/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java	(revision 19226)
+++ trunk/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java	(revision 19227)
@@ -5,14 +5,19 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.actions.mapmode.ParallelWayAction.Mode;
 import org.openstreetmap.josm.actions.mapmode.ParallelWayAction.Modifier;
+import org.openstreetmap.josm.data.UndoRedoHandler;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.testutils.MapModeUtils;
 import org.openstreetmap.josm.testutils.annotations.Main;
 import org.openstreetmap.josm.testutils.annotations.Projection;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
@@ -22,4 +27,17 @@
 @Projection
 class ParallelWayActionTest {
+    private MapFrame map;
+    private ParallelWayAction mapMode;
+    private DataSet dataSet;
+
+    @BeforeEach
+    void setup() {
+        OsmDataLayer layer = new OsmDataLayer(new DataSet(), "ParallelWayActionTest", null);
+        MainApplication.getLayerManager().addLayer(layer);
+        this.map = MainApplication.getMap();
+        this.mapMode = new ParallelWayAction(this.map);
+        this.dataSet = layer.getDataSet();
+    }
+
     /**
      * Unit test of {@link ParallelWayAction#enterMode} and {@link ParallelWayAction#exitMode}.
@@ -27,16 +45,27 @@
     @Test
     void testMode() {
-        OsmDataLayer layer = new OsmDataLayer(new DataSet(), "", null);
-        try {
-            MainApplication.getLayerManager().addLayer(layer);
-            MapFrame map = MainApplication.getMap();
-            ParallelWayAction mapMode = new ParallelWayAction(map);
-            MapMode oldMapMode = map.mapMode;
-            assertTrue(map.selectMapMode(mapMode));
-            assertEquals(mapMode, map.mapMode);
-            assertTrue(map.selectMapMode(oldMapMode));
-        } finally {
-            MainApplication.getLayerManager().removeLayer(layer);
-        }
+        final MapMode oldMapMode = this.map.mapMode;
+        assertTrue(this.map.selectMapMode(mapMode));
+        assertEquals(this.mapMode, this.map.mapMode);
+        assertTrue(this.map.selectMapMode(oldMapMode));
+    }
+
+    /**
+     * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/20908">#20908</a>
+     */
+    @Test
+    void testNonRegression20908() {
+        Logging.clearLastErrorAndWarnings();
+        this.map.selectMapMode(this.map.mapModeDraw);
+        MapModeUtils.clickAt(LatLon.ZERO);
+        MapModeUtils.clickAt(2, new LatLon(0.0001, 0));
+        assertEquals(3, this.dataSet.allPrimitives().size());
+        this.map.selectMapMode(mapMode);
+        MapModeUtils.dragFromTo(new LatLon(0.00005, 0), new LatLon(0.00005, 0.0001));
+        assertEquals(6, this.dataSet.allPrimitives().size());
+        UndoRedoHandler.getInstance().undo();
+        assertEquals(3, this.dataSet.allPrimitives().size());
+        this.map.mapMode.mousePressed(MapModeUtils.mouseClickAt(new LatLon(0.00005, 0.0001)));
+        assertTrue(Logging.getLastErrorAndWarnings().isEmpty(), String.join("\n", Logging.getLastErrorAndWarnings()));
     }
 
Index: trunk/test/unit/org/openstreetmap/josm/testutils/MapModeUtils.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/testutils/MapModeUtils.java	(revision 19227)
+++ trunk/test/unit/org/openstreetmap/josm/testutils/MapModeUtils.java	(revision 19227)
@@ -0,0 +1,103 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.awt.event.MouseEvent;
+
+import org.awaitility.Awaitility;
+import org.awaitility.Durations;
+import org.openstreetmap.josm.data.coor.ILatLon;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+
+/**
+ * Utils for doing stuff in the {@link org.openstreetmap.josm.actions.mapmode.MapMode}
+ */
+public final class MapModeUtils {
+    private MapModeUtils() {
+        // Hide the constructor
+    }
+
+    /**
+     * Click at a specified lat/lon
+     * Note that we use {@link org.openstreetmap.josm.actions.mapmode.MapMode} from {@link org.openstreetmap.josm.gui.MapFrame}
+     * from {@link MainApplication#getMap()}.
+     * @param coordinates The coordinates to click at (lat, lon, lat, lon, ...)
+     */
+    public static void clickAt(double... coordinates) {
+        assertEquals(0, coordinates.length % 2, "coordinates must be a multiple of 2");
+        for (int i = 0; i < coordinates.length; i += 2) {
+            clickAt(new LatLon(coordinates[i], coordinates[i + 1]));
+        }
+    }
+
+    /**
+     * Click at a specified lat/lon
+     * Note that we use {@link org.openstreetmap.josm.actions.mapmode.MapMode} from {@link org.openstreetmap.josm.gui.MapFrame}
+     * from {@link MainApplication#getMap()}.
+     * @param coordinates The coordinates to click at
+     */
+    public static void clickAt(ILatLon... coordinates) {
+        assertEquals(0, coordinates.length % 2, "coordinates must be a multiple of 2");
+        for (ILatLon coordinate : coordinates) {
+            clickAt(coordinate);
+        }
+    }
+
+    /**
+     * Click at a specified lat/lon
+     * Note that we use {@link org.openstreetmap.josm.actions.mapmode.MapMode} from {@link org.openstreetmap.josm.gui.MapFrame}
+     * from {@link MainApplication#getMap()}.
+     * @param location The location to click at
+     */
+    public static void clickAt(ILatLon location) {
+        clickAt(1, location);
+    }
+
+    /**
+     * Click at a specified lat/lon
+     * Note that we use {@link org.openstreetmap.josm.actions.mapmode.MapMode} from {@link org.openstreetmap.josm.gui.MapFrame}
+     * from {@link MainApplication#getMap()}.
+     * @param location The location to click at
+     * @param times The number of times to click
+     */
+    public static void clickAt(int times, ILatLon location) {
+        for (int i = 0; i < times; i++) {
+            final var click = mouseClickAt(location);
+            MainApplication.getMap().mapMode.mousePressed(click);
+            MainApplication.getMap().mapMode.mouseReleased(click);
+            GuiHelper.runInEDTAndWait(() -> { /* Sync UI thread */ });
+        }
+    }
+
+    /**
+     * Perform a click-n-drag operation
+     * @param from The originating point
+     * @param to The end point
+     */
+    public static void dragFromTo(ILatLon from, ILatLon to) {
+        MainApplication.getMap().mapMode.mousePressed(mouseClickAt(from));
+        // Some actions wait a period of time to avoid accidental dragging.
+        Awaitility.await().pollDelay(Durations.FIVE_HUNDRED_MILLISECONDS).atLeast(Durations.FIVE_HUNDRED_MILLISECONDS).until(() -> true);
+        MainApplication.getMap().mapMode.mouseDragged(mouseClickAt(from));
+        MainApplication.getMap().mapMode.mouseDragged(mouseClickAt(to));
+        MainApplication.getMap().mapMode.mouseReleased(mouseClickAt(to));
+        GuiHelper.runInEDTAndWait(() -> { /* Sync UI thread */ });
+    }
+
+    /**
+     * Create the click event
+     * @param location The location for the click event
+     * @return The click event
+     */
+    public static MouseEvent mouseClickAt(ILatLon location) {
+        final var mapView = MainApplication.getMap().mapView;
+        mapView.zoomTo(mapView.getCenter(), 0.005);
+        mapView.zoomTo(location);
+        final var point = mapView.getPoint(location);
+        return new MouseEvent(MainApplication.getMap(), Long.hashCode(System.currentTimeMillis()),
+                System.currentTimeMillis(), 0, point.x, point.y, 1, false, MouseEvent.BUTTON1);
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java	(revision 19226)
+++ trunk/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java	(revision 19227)
@@ -87,4 +87,5 @@
         );
     }
+
     /**
      * Test of {@link ExceptionUtil#explainBadRequest} method.
@@ -94,5 +95,7 @@
     @SuppressWarnings("unchecked")
     void testExplainBadRequest(Supplier<String> message, Object exception) {
-        assertEquals(message.get(), ExceptionUtil.explainBadRequest(exception instanceof Supplier ? ((Supplier<OsmApiException>) exception).get() : (OsmApiException) exception));
+        assertEquals(message.get(), ExceptionUtil.explainBadRequest(
+                exception instanceof Supplier ? ((Supplier<OsmApiException>) exception).get() : (OsmApiException) exception
+        ));
     }
 
