ThinkGeo.com    |     Documentation    |     Premium Support

WmtsAsyncLayer stops drawing when zooming in to lower scales

Upgrading WmtsLayer from TG 10 to TG 14. In testing with our Planet data I noticed that it stops drawing when zoomed in too far. Further testing reveals this also happens with other Wmts layers. Usually this happens when the scale is 1:4514 or smaller. The exception is sometimes The HTTP request failed with status code: BadRequest and sometimes Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
.

I have attached a sample project.

Thanks!

Steve

WmtsZoomInProblem.zip (96.5 KB)

Hi Steve,

We recreated the issue, and we found it’s the server starting to return “BadRequest” since zoom17, here is the uri for example:
https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/WMTS?service=WMTS&request=GetTile&version=1.0.0&layer=USGSTopo&style=default&format=image/png&TileMatrixSet=GoogleMapsCompatible&TileMatrix=17&TileRow=52892&TileCol=30292

even this request is valid according to its Capabilities
basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/WMTS?service=WMTS&request=GetCapabilites

I tried RESTFul service and it returns the same result.
https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/WMTS/tile/1.0.0/USGSTopo/default/GoogleMapsCompatible/17/52892/30292

It returns correctly for zoom16 and above.

We didn’t recreate the “Index was out of range/non-negative and less than the size of the collection” issue, does this happen randomly or it happens when zooming into some specific area?

Thanks,
Ben

Hi Ben,

Looks like the problem with the USGSTopo service may be on the server itself. I looked into it a bit more and it looks like the ‘Index out of range’ error is only happening when we access Planet data. I am unable to send a sample project because of the key needed to access the data, but I do have the error and the request Uri for the error:

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<DrawWithoutProjectionConverterAsync>d__48.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<DrawAsyncCore>d__44.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.AsyncLayer.<DrawTranslationAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.AsyncLayer.<DrawAsync>d__6.MoveNext()
RequestUri: https://tiles.planet.com/basemaps/v1/latest-series/473b9b21-5940-45c8-9729-c765619eda4d/gmap/13/1981/3359.png?api_key=&proc=rgb

Anything helpful here?

Thanks!

Steve

Hi Steve,

Please update to the latest beta051 and try again. In this build, the layer should throw a more descriptive exception with a detailed stack trace.

Also, please enable internal logging so we can see whether any internal errors are reported:

ThinkGeoDebugger.LogType  = ThinkGeoLogType.All;
ThinkGeoDebugger.LogLevel = ThinkGeoLogLevel.Error;

Thanks,
Ben

Hi Ben,

Here is the new exception stack trace:

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
   at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at ThinkGeo.Core.WmtsAsyncLayer.GetRequestUri(Int64 x, Int64 y, Int32 zoomLevel)
   at ThinkGeo.Core.WmtsAsyncLayer.GetImageUriAsyncCore(Int32 zoomLevel, Int64 x, Int64 y, Single resolutionFactor)
   at ThinkGeo.Core.WebRasterXyzTileAsyncLayer.<GetImageUriAsync>d__33.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.WebRasterXyzTileAsyncLayer.<GetTileAsyncCore>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<GetTileAsync>d__66.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<GetCloudRasterTileInfoAsync>d__65.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<DrawWithoutProjectionConverterAsync>d__56.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<DrawWithoutProjectionConverterAsync>d__56.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.RasterXyzTileAsyncLayer.<DrawAsyncCore>d__52.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.AsyncLayer.<DrawTranslationAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ThinkGeo.Core.AsyncLayer.<DrawAsync>d__6.MoveNext()

If necessary I can get you a temporary key to access the Planet data. Let me know how I can get it to you.

Thanks!

Steve

That will be great! Can you send it to support@thinkgeo.com?

Hi Ben,

I have sent the key.

Steve

As promised, here is a sample project. You will need to place the key in the code where indicated, in class CustomWmtsLayer.

Thanks!

Steve

Planet_Test.zip (129.8 KB)

Hi Steve,

Thanks for the sample and the key, it’s really helpful!

It seems the TileMatrixSet (GoogleMapsCompatible15) on the server supports zoom 0 ~ 15, so if on the client we zoom in beyond zoom15, that “Index was out of range” exception will be thrown.

We’ve fixed it in the latest beta (v14.5.0-beta055)

  1. Nothing will be displayed (and no exception will be thrown) if zooming into a zoom with no data available on the server.
  2. Write this code
wmtsLayer.RenderBeyondMaxZoom = True

and it will try to fetch the data from the last available zoom. For example rendering Zoom16 from the data of Zoom15

Have a try and let me know what you think.

Thanks,
Ben

Thanks for the fix, works fine now! Do you know when this change will be in a production release?

Steve

It will be v14.5 in May, 2026.

If you don’t want to use beta, can you try the following with your current production release?

wmtsLayer.RenderBeyondMaxZoom = True

// set the MaxZoomOfTheData
var matrixes = wmtsLayer.GetTileMatrixSets();
var maxZoom = matrixes[wmtsLayer.TileMatrixSetName].TileMatrices.Count - 1;
wmtsLayer.MaxZoomOfTheData = maxZoom;

// or just hard code it
// wmtsLayer.MaxZoomOfTheData = 15;