Index: trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java	(revision 14534)
+++ trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java	(revision 14535)
@@ -420,5 +420,11 @@
     }
 
-    protected String detectErrorMessage(String data) {
+    /**
+     * Tries do detect an error message from given string.
+     * @param data string to analyze
+     * @return error message if detected, or null
+     * @since 14535
+     */
+    public String detectErrorMessage(String data) {
         Matcher m = HttpClient.getTomcatErrorMatcher(data);
         return m.matches() ? m.group(1).replace("'", "''") : null;
Index: trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java	(revision 14534)
+++ trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java	(revision 14535)
@@ -67,5 +67,4 @@
      * @param downloadExecutor that will be executing the jobs
      */
-
     public TMSCachedTileLoaderJob(TileLoaderListener listener, Tile tile,
             ICacheAccess<String, BufferedImageCacheEntry> cache,
@@ -321,5 +320,5 @@
 
     @Override
-    protected String detectErrorMessage(String data) {
+    public String detectErrorMessage(String data) {
         Matcher m = SERVICE_EXCEPTION_PATTERN.matcher(data);
         return m.matches() ? removeCdata(Utils.strip(m.group(1))) : super.detectErrorMessage(data);
Index: trunk/src/org/openstreetmap/josm/io/AbstractReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/AbstractReader.java	(revision 14534)
+++ trunk/src/org/openstreetmap/josm/io/AbstractReader.java	(revision 14535)
@@ -14,4 +14,5 @@
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.OptionalLong;
 import java.util.function.Consumer;
 
@@ -323,4 +324,8 @@
             throw new IllegalDataException(e);
         } finally {
+            OptionalLong minId = externalIdMap.values().stream().mapToLong(AbstractPrimitive::getUniqueId).min();
+            if (minId.isPresent() && minId.getAsLong() < AbstractPrimitive.currentUniqueId()) {
+                AbstractPrimitive.advanceUniqueId(minId.getAsLong());
+            }
             progressMonitor.finishTask();
             progressMonitor.removeCancelListener(cancelListener);
@@ -604,10 +609,21 @@
     }
 
+    @SuppressWarnings("unchecked")
+    private <T extends OsmPrimitive> T buildPrimitive(PrimitiveData pd) {
+        OsmPrimitive p;
+        if (pd.getUniqueId() < AbstractPrimitive.currentUniqueId()) {
+            p = pd.getType().newInstance(pd.getUniqueId(), true);
+        } else {
+            p = pd.getType().newVersionedInstance(pd.getId(), pd.getVersion());
+        }
+        p.setVisible(pd.isVisible());
+        p.load(pd);
+        externalIdMap.put(pd.getPrimitiveId(), p);
+        return (T) p;
+    }
+
     private Node addNode(NodeData nd, NodeReader nodeReader) throws IllegalDataException {
-        Node n = new Node(nd.getId(), nd.getVersion());
-        n.setVisible(nd.isVisible());
-        n.load(nd);
+        Node n = buildPrimitive(nd);
         nodeReader.accept(n);
-        externalIdMap.put(nd.getPrimitiveId(), n);
         return n;
     }
@@ -615,5 +631,5 @@
     protected final Node parseNode(double lat, double lon, CommonReader commonReader, NodeReader nodeReader)
             throws IllegalDataException {
-        NodeData nd = new NodeData();
+        NodeData nd = new NodeData(0);
         LatLon ll = null;
         if (areLatLonDefined(lat, lon)) {
@@ -654,10 +670,7 @@
 
     protected final Way parseWay(CommonReader commonReader, WayReader wayReader) throws IllegalDataException {
-        WayData wd = new WayData();
+        WayData wd = new WayData(0);
         commonReader.accept(wd);
-        Way w = new Way(wd.getId(), wd.getVersion());
-        w.setVisible(wd.isVisible());
-        w.load(wd);
-        externalIdMap.put(wd.getPrimitiveId(), w);
+        Way w = buildPrimitive(wd);
 
         Collection<Long> nodeIds = new ArrayList<>();
@@ -672,10 +685,7 @@
 
     protected final Relation parseRelation(CommonReader commonReader, RelationReader relationReader) throws IllegalDataException {
-        RelationData rd = new RelationData();
+        RelationData rd = new RelationData(0);
         commonReader.accept(rd);
-        Relation r = new Relation(rd.getId(), rd.getVersion());
-        r.setVisible(rd.isVisible());
-        r.load(rd);
-        externalIdMap.put(rd.getPrimitiveId(), r);
+        Relation r = buildPrimitive(rd);
 
         Collection<RelationMemberData> members = new ArrayList<>();
Index: trunk/src/org/openstreetmap/josm/io/CachedFile.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/CachedFile.java	(revision 14534)
+++ trunk/src/org/openstreetmap/josm/io/CachedFile.java	(revision 14535)
@@ -5,5 +5,4 @@
 
 import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
@@ -245,14 +244,5 @@
      */
     public byte[] getByteContent() throws IOException {
-        try (InputStream is = getInputStream()) {
-            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-            int nRead;
-            byte[] data = new byte[8192];
-            while ((nRead = is.read(data, 0, data.length)) != -1) {
-                buffer.write(data, 0, nRead);
-            }
-            buffer.flush();
-            return buffer.toByteArray();
-        }
+        return Utils.readBytesFromStream(getInputStream());
     }
 
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 14534)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 14535)
@@ -1447,5 +1447,5 @@
         try {
             ByteArrayOutputStream bout = new ByteArrayOutputStream(stream.available());
-            byte[] buffer = new byte[2048];
+            byte[] buffer = new byte[8192];
             boolean finished = false;
             do {
Index: trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java	(revision 14534)
+++ trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java	(revision 14535)
@@ -4,6 +4,8 @@
 import static org.junit.Assert.assertTrue;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -15,4 +17,7 @@
 import java.util.concurrent.TimeUnit;
 
+import javax.imageio.ImageIO;
+
+import org.apache.commons.jcs.access.CacheAccess;
 import org.junit.Before;
 import org.junit.Rule;
@@ -34,5 +39,7 @@
 import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
 import org.openstreetmap.josm.data.imagery.Shape;
+import org.openstreetmap.josm.data.imagery.TMSCachedTileLoaderJob;
 import org.openstreetmap.josm.data.imagery.TemplatedWMSTileSource;
+import org.openstreetmap.josm.data.imagery.TileJobOptions;
 import org.openstreetmap.josm.data.imagery.WMSEndpointTileSource;
 import org.openstreetmap.josm.data.imagery.WMTSTileSource;
@@ -64,4 +71,5 @@
     private final Set<String> workingURLs = Collections.synchronizedSet(new HashSet<>());
 
+    private TMSCachedTileLoaderJob helper;
     private List<String> ignoredErrors;
 
@@ -72,4 +80,5 @@
     @Before
     public void before() throws IOException {
+        helper = new TMSCachedTileLoaderJob(null, null, new CacheAccess<>(null), new TileJobOptions(0, 0, null, 0), null);
         ignoredErrors = TestUtils.getIgnoredErrorMessages(ImageryPreferenceTestIT.class);
     }
@@ -82,5 +91,5 @@
     }
 
-    private void checkUrl(ImageryInfo info, String url) {
+    private byte[] checkUrl(ImageryInfo info, String url) {
         if (url != null && !url.isEmpty() && !workingURLs.contains(url)) {
             try {
@@ -97,8 +106,19 @@
                     workingURLs.add(url);
                 }
-                response.disconnect();
+                try {
+                    return Utils.readBytesFromStream(response.getContent());
+                } finally {
+                    response.disconnect();
+                }
             } catch (IOException e) {
                 addError(info, url + " -> " + e);
             }
+        }
+        return new byte[0];
+    }
+
+    private void checkLinkUrl(ImageryInfo info, String url) {
+        if (url != null && checkUrl(info, url).length == 0) {
+            addError(info, url + " -> returned empty contents");
         }
     }
@@ -109,5 +129,14 @@
         for (int i = 0; i < 3; i++) {
             try {
-                checkUrl(info, tileSource.getTileUrl(zoom, xy.getXIndex(), xy.getYIndex()));
+                String url = tileSource.getTileUrl(zoom, xy.getXIndex(), xy.getYIndex());
+                byte[] data = checkUrl(info, url);
+                try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
+                    if (ImageIO.read(bais) == null) {
+                        addImageError(info, url, data, "did not return an image");
+                    }
+                } catch (IOException e) {
+                    addImageError(info, url, data, e.toString());
+                    Logging.trace(e);
+                }
                 return;
             } catch (IOException e) {
@@ -125,4 +154,10 @@
             }
         }
+    }
+
+    private void addImageError(ImageryInfo info, String url, byte[] data, String defaultMessage) {
+        // Check if we have received an error message
+        String error = helper.detectErrorMessage(new String(data, StandardCharsets.UTF_8));
+        addError(info, url + " -> " + (error != null ? error : defaultMessage));
     }
 
@@ -184,12 +219,12 @@
         }
 
-        checkUrl(info, info.getAttributionImageURL());
-        checkUrl(info, info.getAttributionLinkURL());
+        checkLinkUrl(info, info.getAttributionImageURL());
+        checkLinkUrl(info, info.getAttributionLinkURL());
         String eula = info.getEulaAcceptanceRequired();
         if (eula != null) {
-            checkUrl(info, eula.replaceAll("\\{lang\\}", ""));
-        }
-        checkUrl(info, info.getPermissionReferenceURL());
-        checkUrl(info, info.getTermsOfUseURL());
+            checkLinkUrl(info, eula.replaceAll("\\{lang\\}", ""));
+        }
+        checkLinkUrl(info, info.getPermissionReferenceURL());
+        checkLinkUrl(info, info.getTermsOfUseURL());
 
         try {
