Skip to content

[widgets/overlay_portal.dart] OverlayPortal semantics tree crashes or behaves unexpectedly on MacOS. #187198

@davidhicks980

Description

@davidhicks980

Steps to reproduce

I'm having trouble getting a consistent replication. I'll share two videos to demonstrate. This bug seems to be related to traversalParentIdentifier, and may be related to #182604. I'm not sure if this is relevant, but I'm running on macOS 15.5

  1. Run example on macOS
  2. Turn on VoiceOver
  3. Open the menu

Expected results

Accessibility focus moves to overlay and buttons and shows the correct semantic boxes around overlay items.

Actual results

Either the AXTree completely crashes, or the semantics rectangles are not properly positioned. Yesterday, the semantics tree always crashed. I'm not sure why it isn't crashing today.

Also, the semantics debugger is not showing the overlay tree. This is due to:

if (node.traversalChildIdentifier != null) {
return;
}

Removing this line shows the correct semantics, so I'm not sure what the issue was:

Image

@chunhtai @QuncCccccc

Code sample

Code sample

First video code snippet:

import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      showSemanticsDebugger: true
      home: Bug()
    )
  );
}

class Bug extends StatelessWidget {
  const Bug({super.key});

  @override
  Widget build(BuildContext context) {
    final controller = OverlayPortalController();
    return Scaffold(
      body: SizedBox(
        width: 50,
        height: 50,
        child: OverlayPortal(
          controller: controller,
          // The massive overlay child is forced to be a logical child of the tiny 50x50 box.
          // This destroys the globalRect matrix and crashes ui::AXTree.
          overlayChildBuilder: (context) {
            return Positioned(
              top: 50,
              left: 50,
              child: Semantics(
                label: 'I will not show in the debugger and crash AXTree',
                child: Container(width: 300, height: 300, color: Colors.red),
              ),
            );
          },
          child: TextButton(onPressed: controller.toggle, child: const Text('Open')),
        ),
      ),
    );
  }
}

Second video code snippet:

void main() => runApp(const SimpleCascadingMenuApp());

/// A Simple Cascading Menu example using the [MenuAnchor] Widget.
class MyCascadingMenu extends StatefulWidget {
  const MyCascadingMenu({super.key});

  @override
  State<MyCascadingMenu> createState() => _MyCascadingMenuState();
}

class _MyCascadingMenuState extends State<MyCascadingMenu> {
  final FocusNode _buttonFocusNode = FocusNode(debugLabel: 'Menu Button');

  @override
  void dispose() {
    _buttonFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MenuAnchor(
      childFocusNode: _buttonFocusNode,
      menuChildren: <Widget>[
        MenuItemButton(onPressed: () {}, child: const Text('Revert')),
        MenuItemButton(onPressed: () {}, child: const Text('Setting')),
        MenuItemButton(onPressed: () {}, child: const Text('Send Feedback')),
      ],
      builder: (_, MenuController controller, Widget? child) {
        return IconButton(
          focusNode: _buttonFocusNode,
          onPressed: () {
            if (controller.isOpen) {
              controller.close();
            } else {
              controller.open();
            }
          },
          icon: const Icon(Icons.more_vert),
        );
      },
    );
  }
}

/// Top Level Application Widget.
class SimpleCascadingMenuApp extends StatelessWidget {
  const SimpleCascadingMenuApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('MenuAnchor Simple Example'),
          leading: const MyCascadingMenu(),
        ),
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

Video 1:

Screen.Recording.2026-05-27.at.3.55.33.PM.mov

Video 2:

Screen.Recording.2026-05-27.at.4.06.16.PM.mov

Logs

The only relevant log is the AXTree drop. I experienced this on every menu yesterday, regardless of whether the semantics debugger was enabled. I'm having trouble replicating it on every run today.

Logs
[ERROR: flutter/shell/platform/common/accessibility_bridge.cc(114)] Failed to update ui::AXTree, error: 4 will not be in the tree and is not the new root

Flutter Doctor output

Doctor output
[✓] Flutter (Channel master, 3.45.0-1.0.pre-201, on macOS 15.5 24F74 darwin-arm64, locale en-US) [1,681ms]
    • Flutter version 3.45.0-1.0.pre-201 on channel master at /Users/davidhicks/fvm/versions/master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 40bfc7cac5 (2 days ago), 2026-05-25 11:59:40 -0400
    • Engine revision 40bfc7cac5
    • Dart version 3.13.0 (build 3.13.0-134.0.dev)
    • DevTools version 2.58.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets,
      enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration, enable-riscv64

[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [2.3s]
    • Android SDK at /Users/davidhicks/Library/Android/sdk
    • Emulator version 36.3.10.0 (build_id 14472402) (CL:N/A)
    • Platform android-36.1, build-tools 36.1.0
    • ANDROID_HOME = /Users/davidhicks/Library/Android/sdk
    • Java binary at: /Users/davidhicks/Library/Java/JavaVirtualMachines/jbr-17.0.14/Contents/Home/bin/java
      This JDK is specified in your Flutter configuration.
      To change the current JDK, run: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment JBR-17.0.14+1-1367.22-nomod (build 17.0.14+1-b1367.22)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 16.4) [1,612ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 16F6
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [6ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (2 available) [6.8s]
    • macOS (desktop) • macos  • darwin-arm64   • macOS 15.5 24F74 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 148.0.7778.179
    ! Error: Browsing on the local area network for David’s iPhone. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources [257ms]
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)fyi-macosFor the attention of macOS platform teamteam-accessibilityOwned by Framework Accessibility team (i.e. responsible for accessibility code in flutter/flutter)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions