Index: trunk/src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java	(revision 9473)
+++ trunk/src/org/openstreetmap/josm/gui/ExceptionDialogUtil.java	(revision 9474)
@@ -354,6 +354,5 @@
 
     /**
-     * Explains a {@link OsmApiException} with a generic error
-     * message.
+     * Explains a {@link OsmApiException} with a generic error message.
      *
      * @param e the exception
@@ -392,5 +391,4 @@
      * @param e the exception
      */
-
     public static void explainNestedUnkonwnHostException(OsmTransferException e) {
         HelpAwareOptionPane.showOptionDialog(
Index: trunk/src/org/openstreetmap/josm/tools/ExceptionUtil.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ExceptionUtil.java	(revision 9473)
+++ trunk/src/org/openstreetmap/josm/tools/ExceptionUtil.java	(revision 9474)
@@ -36,4 +36,8 @@
 import org.openstreetmap.josm.tools.date.DateUtils;
 
+/**
+ * Utilities for exception handling.
+ * @since 2097
+ */
 public final class ExceptionUtil {
 
@@ -43,5 +47,5 @@
 
     /**
-     * handles an exception caught during OSM API initialization
+     * Explains an exception caught during OSM API initialization.
      *
      * @param e the exception
@@ -53,7 +57,14 @@
                 "<html>Failed to initialize communication with the OSM server {0}.<br>"
                 + "Check the server URL in your preferences and your internet connection.",
-                OsmApi.getOsmApi().getServerUrl());
-    }
-
+                OsmApi.getOsmApi().getServerUrl())+"</html>";
+    }
+
+    /**
+     * Explains a {@link OsmApiException} which was thrown because accessing a protected
+     * resource was forbidden.
+     *
+     * @param e the exception
+     * @return The HTML formatted error message to display
+     */
     public static String explainMissingOAuthAccessTokenException(MissingOAuthAccessTokenException e) {
         Main.error(e);
@@ -69,8 +80,10 @@
 
     public static Pair<OsmPrimitive, Collection<OsmPrimitive>> parsePreconditionFailed(String msg) {
+        if (msg == null)
+            return null;
         final String ids = "(\\d+(?:,\\d+)*)";
         final Collection<OsmPrimitive> refs = new TreeSet<>(); // error message can contain several times the same way
         Matcher m;
-        m = Pattern.compile(".*Node (\\d+) is still used by relations " + ids + ".*").matcher(msg);
+        m = Pattern.compile(".*Node (\\d+) is still used by relations? " + ids + ".*").matcher(msg);
         if (m.matches()) {
             OsmPrimitive n = new Node(Long.parseLong(m.group(1)));
@@ -80,5 +93,5 @@
             return Pair.create(n, refs);
         }
-        m = Pattern.compile(".*Node (\\d+) is still used by ways " + ids + ".*").matcher(msg);
+        m = Pattern.compile(".*Node (\\d+) is still used by ways? " + ids + ".*").matcher(msg);
         if (m.matches()) {
             OsmPrimitive n = new Node(Long.parseLong(m.group(1)));
@@ -96,5 +109,5 @@
             return Pair.create(n, refs);
         }
-        m = Pattern.compile(".*Way (\\d+) is still used by relations " + ids + ".*").matcher(msg);
+        m = Pattern.compile(".*Way (\\d+) is still used by relations? " + ids + ".*").matcher(msg);
         if (m.matches()) {
             OsmPrimitive n = new Way(Long.parseLong(m.group(1)));
@@ -240,4 +253,11 @@
     }
 
+    /**
+     * Explains a {@link OsmApiException} which was thrown because the authentication at
+     * the OSM server failed, with basic authentication.
+     *
+     * @param e the exception
+     * @return The HTML formatted error message to display
+     */
     public static String explainFailedBasicAuthentication(OsmApiException e) {
         Main.error(e);
@@ -250,4 +270,11 @@
     }
 
+    /**
+     * Explains a {@link OsmApiException} which was thrown because the authentication at
+     * the OSM server failed, with OAuth authentication.
+     *
+     * @param e the exception
+     * @return The HTML formatted error message to display
+     */
     public static String explainFailedOAuthAuthentication(OsmApiException e) {
         Main.error(e);
@@ -260,9 +287,16 @@
     }
 
+    /**
+     * Explains a {@link OsmApiException} which was thrown because accessing a protected
+     * resource was forbidden (HTTP 403), without OAuth authentication.
+     *
+     * @param e the exception
+     * @return The HTML formatted error message to display
+     */
     public static String explainFailedAuthorisation(OsmApiException e) {
         Main.error(e);
         String header = e.getErrorHeader();
         String body = e.getErrorBody();
-        String msg = null;
+        String msg;
         if (header != null) {
             if (body != null && !header.equals(body)) {
@@ -291,4 +325,11 @@
     }
 
+    /**
+     * Explains a {@link OsmApiException} which was thrown because accessing a protected
+     * resource was forbidden (HTTP 403), with OAuth authentication.
+     *
+     * @param e the exception
+     * @return The HTML formatted error message to display
+     */
     public static String explainFailedOAuthAuthorisation(OsmApiException e) {
         Main.error(e);
@@ -356,7 +397,5 @@
         String msg = e.getErrorHeader();
         if (msg != null) {
-            String pattern = "The changeset (\\d+) was closed at (.*)";
-            Pattern p = Pattern.compile(pattern);
-            Matcher m = p.matcher(msg);
+            Matcher m = Pattern.compile("The changeset (\\d+) was closed at (.*)").matcher(msg);
             if (m.matches()) {
                 long changesetId = Long.parseLong(m.group(1));
@@ -392,5 +431,5 @@
                     "<html>The server reported that it has detected a conflict.");
         }
-        return msg;
+        return msg.endsWith("</html>") ? msg : (msg + "</html>");
     }
 
@@ -449,5 +488,5 @@
         return tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''<br>"
                 + "for security reasons. This is most likely because you are running<br>"
-                + "in an applet and because you did not load your applet from ''{1}''.", apiUrl, host);
+                + "in an applet and because you did not load your applet from ''{1}''.", apiUrl, host)+"</html>";
     }
 
@@ -463,5 +502,5 @@
         Main.error(e);
         return tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''.<br>"
-                + "Please check your internet connection.", e.getUrl());
+                + "Please check your internet connection.", e.getUrl())+"</html>";
     }
 
@@ -479,6 +518,6 @@
         return tr("<html>Failed to upload data to or download data from<br>" + "''{0}''<br>"
                 + "due to a problem with transferring data.<br>"
-                + "Details (untranslated): {1}</html>", e.getUrl(), ioe
-                .getMessage());
+                + "Details (untranslated): {1}</html>", e.getUrl(),
+                ioe != null ? ioe.getMessage() : "null");
     }
 
@@ -495,5 +534,5 @@
         return tr("<html>Failed to download data. "
                 + "Its format is either unsupported, ill-formed, and/or inconsistent.<br>"
-                + "<br>Details (untranslated): {0}</html>", ide.getMessage());
+                + "<br>Details (untranslated): {0}</html>", ide != null ? ide.getMessage() : "null");
     }
 
@@ -510,10 +549,10 @@
         Main.error(e);
         return tr("<html>Failed to download data.<br>"
-                + "<br>Details: {0}</html>", oae.getMessage());
+                + "<br>Details: {0}</html>", oae != null ? oae.getMessage() : "null");
     }
 
     /**
      * Explains a {@link OsmApiException} which was thrown because of an internal server
-     * error in the OSM API server..
+     * error in the OSM API server.
      *
      * @param e the exception
@@ -523,5 +562,5 @@
         Main.error(e);
         return tr("<html>The OSM server<br>" + "''{0}''<br>" + "reported an internal server error.<br>"
-                + "This is most likely a temporary problem. Please try again later.", e.getUrl());
+                + "This is most likely a temporary problem. Please try again later.", e.getUrl())+"</html>";
     }
 
@@ -613,5 +652,5 @@
         return tr("<html>Failed to open a connection to the remote server<br>" + "''{0}''.<br>"
                 + "Host name ''{1}'' could not be resolved. <br>"
-                + "Please check the API URL in your preferences and your internet connection.", apiUrl, host);
+                + "Please check the API URL in your preferences and your internet connection.", apiUrl, host)+"</html>";
     }
 
@@ -708,4 +747,3 @@
         }
     }
-
 }
