Search code examples
javascriptleaflet

Leaflet does not load alternative image for some HTTP error


I'm using Leaflet and sometimes I run into some issues while trying to load tiles.

So I tend to use an option offered from Leaflet so that I load a default image whenever an error happens.

But I don't know why it is not working for 400 HTTP response (and perhaps even others)? Instead Leaflet displays a huge '400' which clearly I don't desire.

How can I solve it? I'd prefer if Leaflet loaded the alternative image for any error response.

Here's an example of code where the default image (a simple black one) is loaded for 404 HTTP response while not for 400 HTTP response.

var map1 = L.map('map1').setView([50,0], 5);

//tile that generates 400 error
L.tileLayer("https://tile.gbif.org/3575/omt/0/-1/[email protected]?style=gbif-light", 
{
    tileSize: 512,
    maxZoom: 16,
    attribution: '© OpenStreetMap',
    errorTileUrl: "https://th.bing.com/th/id/R.cae2b472a6f1cdaa99d25136227d32e1?rik=30v5m3kfjICf8w&riu=http%3a%2f%2fwww.drodd.com%2fimages16%2fblack-picture10.jpg&ehk=J5mSS4MRPrrwCcMS%2bD9rP0sKuJxWfRxopWEGC7KPgg0%3d&risl=&pid=ImgRaw&r=0"
}).addTo(map1);

//tile that generates 404 error
var map2 = L.map('map2').setView([50,0], 5);
L.tileLayer("https://tile.gbif.org/3575/omt/2/0/[email protected]?style=gbif-light", 
{
    tileSize: 512,
    maxZoom: 16,
    attribution: '© OpenStreetMap',
    errorTileUrl: "https://th.bing.com/th/id/R.cae2b472a6f1cdaa99d25136227d32e1?rik=30v5m3kfjICf8w&riu=http%3a%2f%2fwww.drodd.com%2fimages16%2fblack-picture10.jpg&ehk=J5mSS4MRPrrwCcMS%2bD9rP0sKuJxWfRxopWEGC7KPgg0%3d&risl=&pid=ImgRaw&r=0"
}).addTo(map2);
<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin=""/>
        <script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script>
        <title>Test on map</title>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
        <script src="script.js" defer></script>
        <style>
        #map1, #map2 {
            width: 600px;
            height: 600px;
        }
        </style>
    </head>
    <body>
        <div id="map1"></div>
        <div id="map2"></div>
    </body>
</html>


Solution

  • It looks like your Tile Server still sends an image as payload to the https://tile.gbif.org/3575/omt/0/-1/[email protected]?style=gbif-light tile request, while also sending a 400 error code in the response header:

    https://tile.gbif.org/3575/omt/0/-1/[email protected]?style=gbif-light

    Image actually still returned by server

    So the big "400" image actually comes from the Tile Server, it is not generated by Leaflet itself.

    Unfortunately, when such an inconsistent response is received, only the "load" event on the <img> Element is fired, whereas the "error" event remains silent:

    const img = document.createElement('img')
    img.onerror = () => console.log('error')
    img.onload = () => console.log('load')
    img.src = 'https://tile.gbif.org/3575/omt/0/-1/[email protected]?style=gbif-light'

    Therefore, Leaflet has no way to know that the server also sent the error code, it sees only the image payload, and displays it as a legit tile image.