Skip to content

[Google3 Bug] _TypeError crash in _RenderObjectSemantics._buildSemanticsSubtree #184036

Closed

Description

@math1man

Help us understand the severity of this issue

  • causing severe production issues e.g. malfunctions or data loss
  • blocking next binary release
  • blocking a client feature launch within a quarter
  • nice-to-have but does not block a launch within the next quarter

Steps to reproduce

Unclear

Expected results

App does not crash

Actual results

~1000 crashes per day in production with the following stack trace:

_TypeError
at _RenderObjectSemantics._buildSemanticsSubtree	(object.dart:6235)
at PipelineOwner.flushSemantics	(object.dart:1625)
at PipelineOwner.flushSemantics	(object.dart:1642)
at RendererBinding.drawFrame	(binding.dart:636)
at WidgetsBinding.drawFrame	(binding.dart:1564)
at RendererBinding._handlePersistentFrameCallback	(binding.dart:495)
at RendererBinding._handlePersistentFrameCallback	(binding.dart:494)
at SchedulerBinding._invokeFrameCallback	(binding.dart:1430)
at SchedulerBinding.handleDrawFrame	(binding.dart:1345)
at SchedulerBinding._handleDrawFrame	(binding.dart:1198)
at SchedulerBinding._handleDrawFrame	(binding.dart:1180)
at _rootRun	(zone_root.dart:35)
at _rootRun	(zone_root.dart:26)
at _CustomZone.run	(zone.dart:726)
at _CustomZone.runGuarded	(zone.dart:625)
at _invoke	(hooks.dart:425)
at PlatformDispatcher._drawFrame	(platform_dispatcher.dart:447)
at _drawFrame	(hooks.dart:395)
at _drawFrame	(hooks.dart:393)

I believe the root cause is the geometry! invocation from https://github.com/flutter/flutter/pull/180375/changes#diff-4c298197a8aa7831a26eece096c8b8b07773ba1f5376d848ea4ef2924b606e9fR6235

Code sample

None

Screenshots or Video

None

Logs

N/A, google3 internal

Flutter Doctor output

N/A, google3 internal

Activity

  1. math1man commented on Mar 23, 2026

    @math1man
    ContributorAuthor

    Internal bug b/494797304, client huggsy

  2. added
    in triagePresently being triaged by the triage team
    c: crashStack traces logged to the console
    frameworkflutter/packages/flutter repository. See also f: labels.
    a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)
    team-accessibilityOwned by Framework Accessibility team (i.e. responsible for accessibility code in flutter/flutter)
    and removed
    in triagePresently being triaged by the triage team
    on Mar 23, 2026
  3. mbcorona commented on Mar 23, 2026

    @mbcorona
    Member

    Routing to team-accessibility since the stack trace specifically fails at _RenderObjectSemantics._buildSemanticsSubtree

  4. changed the title [-][Google3 Bug]:[/-] [+][Google3 Bug] _TypeError crash in _RenderObjectSemantics._buildSemanticsSubtree[/+] on Mar 23, 2026
  5. self-assigned this
    on Mar 25, 2026
  6. added
    P1High-priority issues at the top of the work list
    on Mar 25, 2026
  7. chunhtai commented on Mar 27, 2026

    @chunhtai
    Contributor

    Response from AI assistant:

    This is a valid accessibility bug in the Flutter framework, causing a _TypeError crash at _RenderObjectSemantics._buildSemanticsSubtree (object.dart:6235) when a semantic node enters a siblingMergeGroups with a dirty (null) geometry. Because updateChildren() fails to schedule an explicit child within a siblingMergeGroups for a geometry update, it cascades to a null assertion runtime failure.

    1. Reproducible Test Case
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      testWidgets('Reproduce null geometry in siblingMergeGroups', (WidgetTester tester) async {
        const SemanticsTag first = SemanticsTag('1');
        const SemanticsTag second = SemanticsTag('2');
        ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
          final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
          final List<SemanticsConfiguration> sibling = <SemanticsConfiguration>[];
          for (final SemanticsConfiguration config in configs) {
            if (config.tagsChildrenWith(first) || config.tagsChildrenWith(second)) {
              sibling.add(config);
            } else {
              builder.markAsMergeUp(config);
            }
          }
          builder.markAsSiblingMergeGroup(sibling);
          return builder.build();
        }
    
        final StateSetterBuilder parentSetter = StateSetterBuilder();
        double size = 100.0;
    
        await tester.pumpWidget(
          Directionality(
            textDirection: TextDirection.ltr,
            child: Semantics(
              label: 'parent',
              child: parentSetter.build(
                (BuildContext context, void Function(void Function()) setState) {
                  return SizedBox(
                    width: size,
                    height: size,
                    child: TestConfigDelegate(
                      delegate: delegate,
                      child: Column(
                        children: <Widget>[
                          Semantics(label: '1', tagForChildren: first, child: const SizedBox(width: 10, height: 10)),
                          Semantics(label: '2', tagForChildren: second, child: const SizedBox(width: 10, height: 10)),
                        ],
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        );
    
        // Now trigger markNeedsSemanticsGeometryUpdate on the parent.
        // Changing the size of the outer SizedBox will make the tree structurally dirty for geometry.
        parentSetter.update(() {
          size = 200.0;
        });
        
        // The framework will run flushSemantics.
        await tester.pump();
      });
    }
    
    class StateSetterBuilder {
      void Function(void Function())? _setState;
      Widget build(Widget Function(BuildContext, void Function(void Function())) builder) {
        return StatefulBuilder(
          builder: (BuildContext context, void Function(void Function()) setState) {
            _setState = setState;
            return builder(context, setState);
          },
        );
      }
      void update(void Function() fn) {
        _setState!(fn);
      }
    }
    
    class TestConfigDelegate extends SingleChildRenderObjectWidget {
      const TestConfigDelegate({super.key, required this.delegate, super.child});
      final ChildSemanticsConfigurationsDelegate delegate;
    
      @override
      RenderTestConfigDelegate createRenderObject(BuildContext context) =>
          RenderTestConfigDelegate(delegate: delegate);
    
      @override
      void updateRenderObject(BuildContext context, RenderTestConfigDelegate renderObject) {
        if (renderObject.delegate != delegate) {
          renderObject.delegate = delegate;
          renderObject.markNeedsSemanticsUpdate();
        }
      }
    }
    
    class RenderTestConfigDelegate extends RenderProxyBox {
      RenderTestConfigDelegate({required ChildSemanticsConfigurationsDelegate delegate}) : _delegate = delegate;
    
      ChildSemanticsConfigurationsDelegate get delegate => _delegate;
      ChildSemanticsConfigurationsDelegate _delegate;
      set delegate(ChildSemanticsConfigurationsDelegate value) {
        if (value != _delegate) {
          _delegate = value;
          markNeedsSemanticsUpdate();
        }
      }
    
      @override
      void describeSemanticsConfiguration(SemanticsConfiguration config) {
        super.describeSemanticsConfiguration(config);
        config.childConfigurationsDelegate = delegate;
      }
    }
    2. Proposed Fix in Framework (packages/flutter/lib/src/rendering/object.dart)

    In _RenderObjectSemantics.updateChildren(), iterate over elements inside siblingMergeGroups and check for missing geometry. If found, add them to _nodesNeedingSemanticsGeometryUpdate list:

        // Current loop in updateChildren handles result.$1 (mergeUp group):
        for (final _RenderObjectSemantics childSemantics
            in result.$1.whereType<_RenderObjectSemantics>()) {
            if (childSemantics.geometryDirty) {
              renderObject.owner!._nodesNeedingSemanticsGeometryUpdate.add(childSemantics.renderObject);
            }
            // ... evaluates nodes in mergeUp group
        }
    
        // proposed addition directly after the above:
        for (final _RenderObjectSemantics explicitSiblingChild
            in siblingMergeGroups
                .expand<_SemanticsFragment>((List<_SemanticsFragment> group) => group)
                .whereType<_RenderObjectSemantics>()
                .expand(
                  (_RenderObjectSemantics siblingChild) => siblingChild.shouldFormSemanticsNode
                      ? <_RenderObjectSemantics>[siblingChild]
                      : siblingChild._children,
                )) {
          if (explicitSiblingChild.geometryDirty) {
            renderObject.owner!._nodesNeedingSemanticsGeometryUpdate.add(explicitSiblingChild.renderObject);
          }
        }

    Component: framework
    Labels needed: framework

  8. github-actions commented on Apr 13, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  9. locked as resolved and limited conversation to collaborators on Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)c: crashStack traces logged to the consolecustomer: googleVarious Google teamsframeworkflutter/packages/flutter repository. See also f: labels.team-accessibilityOwned by Framework Accessibility team (i.e. responsible for accessibility code in flutter/flutter)triaged-accessibilityTriaged by Framework Accessibility team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions