Skip to content

iOS: RenderBox was not laid out — unguarded currentContext?.size in async onPlatformViewCreated becomes an uncatchable fatal (2.18.0-2.28.0) #1141

Description

@luis-calupet

On iOS, _MapWidgetState.onPlatformViewCreated reads key.currentContext?.size while the platform view can be mounted but not yet laid out. Element.size throws RenderBox was not laid out in that state — the ?. only guards a null context, not an unlaid-out element. Because onPlatformViewCreated is async with no await before the read, the synchronous throw is captured into a Future that DarwinViewState._createNewUiKitView discards along with its try/catch — so the error surfaces as an unhandled-zone fatal that no app-side try/catch can intercept, with zero app frames in the trace.

Affected code

lib/src/map_widget.dart — present at least from 2.18.0 (line 329) through 2.23.0 (line 337) and still unguarded in 2.28.0 (line 350):

Future<void> onPlatformViewCreated(int id) async {
  ...
  // WARNING: Because platform view is not sized at this moment on iOS,
  // it is not safe to call methods that depend on the size of the platform view,
  ...
  final size = key.currentContext?.size;   // <-- throws when mounted but not laid out
  if (size != null) {
    await _mapboxMapsPlatform.submitViewSizeHint(
        width: size.width, height: size.height);
  }
  ...
}

The method's own WARNING comment already states the view is not sized at this moment — but Element.size on a render box whose layout has not completed does not return null; it throws.

Reproduction shape

A MapWidget mounts while a route transition is still in flight (e.g. a screen containing the map is pushed and the platform view is created before first layout of the new route completes). We see this in production crash reporting (Sentry) as level: fatal, RenderBox was not laid out, with no application frames — which is exactly the discarded-Future mechanism above. 7 events / 5 distinct users on our iOS build over ~1 week, reproducing across app versions.

Suggested fix

Any of:

  • guard the read: final ctx = key.currentContext; final box = ctx?.findRenderObject(); final size = (box is RenderBox && box.hasSize) ? box.size : null;
  • defer the size-hint to a post-frame callback when layout hasn't completed;
  • or make the read part of an awaited chain so a failure is at least observable/handleable rather than an unhandled zone error.

The size hint is an optimization, so a null/deferred fallback is safe — considerably safer than an uncatchable fatal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions