Subject: [PATCH] #23478
---
Index: src/org/openstreetmap/josm/tools/bugreport/ReportedException.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java b/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java
--- a/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java	(revision 18986)
+++ b/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java	(date 1708015135088)
@@ -10,6 +10,7 @@
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -18,9 +19,13 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.function.Supplier;
+import java.util.stream.Collectors;
 
+import org.openstreetmap.josm.io.NetworkManager;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.StreamUtils;
+import org.openstreetmap.josm.tools.TextUtils;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
  * This is a special exception that cannot be directly thrown.
@@ -73,6 +78,54 @@
             Logging.log(Logging.LEVEL_ERROR, "Unable to get thread stack traces", e);
         }
         this.caughtOnThread = caughtOnThread;
+        try {
+            this.addProblemUrl();
+            // TODO Remove try-catch block in 2025; we very specifically want to avoid a case where something
+            // causes an exception and prevents the exception from being reported.
+            // I think this is unnecessary, but it is better to be paranoid here.
+        } catch (Exception e) {
+            this.getCause().addSuppressed(e);
+        }
+    }
+
+    /**
+     * Check to see if the {@link NetworkManager} has any errors related to this exception
+     * @since xxx
+     */
+    private void addProblemUrl() {
+        final String urls = NetworkManager.getNetworkErrors().entrySet().stream()
+            .filter(entry -> mayHaveCaused(new HashSet<>(), this, entry.getValue()))
+            .map(Map.Entry::getKey)
+            .map(TextUtils::stripUrl)
+            .collect(Collectors.joining("\n"));
+        if (!Utils.isBlank(urls)) {
+            put("urls", urls);
+        }
+    }
+
+    /**
+     * Check if the other throwable may have caused this exception
+     * @param visited The exceptions visited so far for {@code other}. This should (hopefully) avoid issues where
+     *                someone has the bright idea of suppressing an exception using an exception that it suppressed.
+     * @param throwable The current throwable to check
+     * @param other The other exception to check
+     * @return {@code true} if the other exception is in this exceptions stack
+     */
+    private static boolean mayHaveCaused(Set<Throwable> visited, Throwable throwable, Throwable other) {
+        Throwable current = throwable;
+        while (current != null) {
+            if (current == other) {
+                return true;
+            }
+            visited.add(current);
+            for (Throwable suppressed : current.getSuppressed()) {
+                if (mayHaveCaused(visited, suppressed, other)) {
+                    return true;
+                }
+            }
+            current = current.getCause();
+        }
+        return false;
     }
 
     /**
