Skip to content

No-service-area layer setup is not idempotent / race-safe on repeated style loads (sourceAlreadyExists & styleNotFound) #13

Description

@JulianBissekkou

Summary

When a RouteMap configured with a non-empty noServiceAreaLayers list reloads its
style more than once during the lifetime of a single map instance, the plugin throws
unhandled PlatformExceptions. Two distinct exceptions have been observed, and both are
rooted in style-loaded handling that is not idempotent and not race-safe against
repeated or overlapping style loads.

A style (re)load happens whenever styleUrl changes at runtime (for example switching
between a light and a dark map style), or when the underlying MapLibreMap platform view
re-emits onStyleLoaded — which can happen while the map is embedded in an animated /
modal container, or when the widget subtree is rebuilt and/or torn down and recreated in
quick succession.

Observed exceptions

A) sourceAlreadyExists — no-service-area sources are re-added without removal

PlatformException(sourceAlreadyExists, Source already exists, Source with id no_service_area_source_id_0 already exists., null)
#0 StandardMethodCodec.decodeEnvelope (message_codecs.dart:653)
#1 MethodChannel._invokeMethod (platform_channel.dart:366)
#2 MapLibreMethodChannel.addSource (method_channel_maplibre_gl.dart:940)
#3 _RouteMapNoServiceAreaLayerState._addNoServiceAreaLayer (route_map_no_service_area_layer.dart:48)
#4 _RouteMapNoServiceAreaLayerState._addNoServiceAreaLayers (route_map_no_service_area_layer.dart:11)
#5 _RouteMapState.build.<anonymous closure> (route_map_base.dart:321)

B) styleNotFound — annotation manager re-initialized against a torn-down style

PlatformException(styleNotFound, Style not found, Style not found., null)
#0 StandardMethodCodec.decodeEnvelope (message_codecs.dart:653)
#1 MethodChannel._invokeMethod (platform_channel.dart:366)
#2 MapLibreMethodChannel.addGeoJsonSource (method_channel_maplibre_gl.dart:758)
#3 MapLibreMapController.addGeoJsonSource (controller.dart:451)
#4 AnnotationManager.initialize (annotation_manager.dart:83)
#5 new MapLibreMapController.<anonymous closure> (controller.dart:235)

Exception A is raised by route_map itself. Exception B is raised inside maplibre_gl's
annotation-manager initialization, but it is driven by the same trigger (repeated /
overlapping style loads), so the two tend to appear together.

Steps to reproduce

  1. Build a RouteMap with a non-empty noServiceAreaLayers list.
  2. Make the same map instance load its style at least twice, e.g.:
    • change styleUrl at runtime (light ↔ dark), and/or
    • embed the map in a modal / animated container and open it, and/or rebuild the
      surrounding subtree rapidly (frequent state updates).
  3. Observe the exceptions in the logs.

Expected

Repeated style loads re-apply the no-service-area layers cleanly (remove-then-add), and
in-flight style-loaded work does not crash if the style is superseded or disposed while
async work is still running. No unhandled PlatformException.

Actual

  • sourceAlreadyExists for no_service_area_source_id_0 on the second style load
    (and, as a side effect, a duplicated grey no-service-area overlay can remain on the map).
  • styleNotFound when annotation managers are (re)initialized while the style is being
    swapped / torn down.

Suspected cause (short)

_addNoServiceAreaLayers re-adds sources/layers with fixed, index-based IDs without
removing the previous ones first and without any try/catch or re-entrancy guard
— unlike
the POI-layer path, which already removes-before-add and swallows removal errors. A full
root-cause walkthrough (with file/line references and suggested fixes for both exceptions)
is in a comment below.

Environment

  • route_map: feature/native-location-display @ 60683a2
  • maplibre_gl: 0.26.2 (git, custom branch)
  • Flutter: 3.41.3
  • Platform: Android & iOS (failure originates on the native/method-channel side)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions