# Buggy code
def get_image(self, tile):
    if six.PY3:
        from urllib.request import urlopen
    else:
        from urllib2 import urlopen

    url = self._image_url(tile)

    fh = urlopen(url)
    im_data = six.BytesIO(fh.read())
    fh.close()
    img = Image.open(im_data)

    img = img.convert(self.desired_tile_form)

    return img, self.tileextent(tile), "lower"


# Traceback (ValueError)
ValueError                                Traceback (most recent call last)
~/miniconda3/envs/education/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
339                 pass
340             else:
--> 341                 return printer(obj)
342             # Finally look for special method names
343             method = get_real_method(obj, self.print_method)

~/miniconda3/envs/education/lib/python3.7/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
242
243     if 'png' in formats:
--> 244         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
245     if 'retina' in formats or 'png2x' in formats:
246         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/miniconda3/envs/education/lib/python3.7/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
126
127     bytes_io = BytesIO()
--> 128     fig.canvas.print_figure(bytes_io, **kw)
129     data = bytes_io.getvalue()
130     if fmt == 'svg':

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, **kwargs)
2054                         orientation=orientation,
2055                         dryrun=True,
-> 2056                         **kwargs)
2057                     renderer = self.figure._cachedRenderer
2058                     bbox_artists = kwargs.pop("bbox_extra_artists", None)

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in print_png(self, filename_or_obj, metadata, pil_kwargs, *args, **kwargs)
525
526         else:
--> 527             FigureCanvasAgg.draw(self)
528             renderer = self.get_renderer()
529             with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py in draw(self)
386         self.renderer = self.get_renderer(cleared=True)
387         with RendererAgg.lock:
--> 388             self.figure.draw(self.renderer)
389             # A GUI class may be need to update a window using this draw, so
390             # don't forget to call the superclass.

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
36                 renderer.start_filter()
37
---> 38             return draw(artist, renderer, *args, **kwargs)
39         finally:
40             if artist.get_agg_filter() is not None:

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/figure.py in draw(self, renderer)
1707             self.patch.draw(renderer)
1708             mimage._draw_list_compositing_images(
-> 1709                 renderer, self, artists, self.suppressComposite)
1710
1711             renderer.close_group('figure')

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
133     if not_composite or not has_images:
134         for a in artists:
--> 135             a.draw(renderer)
136     else:
137         # Composite any adjacent images together

~/miniconda3/envs/education/lib/python3.7/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
36                 renderer.start_filter()
37
---> 38             return draw(artist, renderer, *args, **kwargs)
39         finally:
40             if artist.get_agg_filter() is not None:

~/miniconda3/envs/education/lib/python3.7/site-packages/cartopy/mpl/geoaxes.py in draw(self, renderer, inframe)
380             for factory, args, kwargs in self.img_factories:
381                 img, extent, origin = factory.image_for_domain(
--> 382                     self._get_extent_geom(factory.crs), args[0])
383                 self.imshow(img, extent=extent, origin=origin,
384                             transform=factory.crs, *args[1:], **kwargs)

~/miniconda3/envs/education/lib/python3.7/site-packages/cartopy/io/img_tiles.py in image_for_domain(self, target_domain, target_z)
66             tiles.append([img, x, y, origin])
67
---> 68         img, extent, origin = _merge_tiles(tiles)
69         return img, extent, origin
70

~/miniconda3/envs/education/lib/python3.7/site-packages/cartopy/io/img_tiles.py in _merge_tiles(tiles)
503     """Return a single image, merging the given images."""
504     if not tiles:
--> 505         raise ValueError('A non-empty list of tiles should '
506                          'be provided to merge.')
507     xset = [set(x) for i, x, y, _ in tiles]

ValueError: A non-empty list of tiles should be provided to merge.

# Fixed code
def get_image(self, tile):
    if six.PY3:
        from urllib.request import urlopen, Request, HTTPError, URLError
    else:
        from urllib2 import urlopen, Request, HTTPError, URLError

    url = self._image_url(tile)
    try:
        request = Request(url, headers={"user-agent": self.user_agent})
        fh = urlopen(request)
        im_data = six.BytesIO(fh.read())
        fh.close()
        img = Image.open(im_data)

    except (HTTPError, URLError) as err:
        print(err)
        img = Image.fromarray(np.full((256, 256, 3), (250, 250, 250), dtype=np.uint8))

    img = img.convert(self.desired_tile_form)
    return img, self.tileextent(tile), "lower"