<p dir="auto">If I use a <code class="notranslate">Navigator</code> as a child of a <code class="notranslate">TabBarView</code>, and that <code class="notranslate">Navigator</code> uses a <code class="notranslate">GlobalKey</code>, then there is a situation where <code class="notranslate">Element.updateChild</code> is called, and this causes a spurious assert that</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Multiple widgets used the same GlobalKey&quot;."><pre class="notranslate"><code class="notranslate">Multiple widgets used the same GlobalKey".
</code></pre></div>
<p dir="auto">Here is some code that demonstrates the problem. Run the following app, and after it starts up, hit tab "C" to see the error.</p>
<div class="highlight highlight-source-dart notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import 'package:flutter/material.dart';

void main() =&gt; runApp(MyApp());

class MyApp extends StatelessWidget {

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() =&gt; _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {
  GlobalKey globalKeyA = GlobalKey(debugLabel: 'A');

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: TabBarView(
            children: [
              Navigator(
                key: globalKeyA,
                onGenerateRoute: (_) =&gt; 
                  MaterialPageRoute(
                    settings: RouteSettings(
                      isInitialRoute: true
                    ),
                    builder: (context) =&gt; Text('Page A'),
                  )
              ),
              Text('Page B'),
              Text('Page C'),

            ]
          ),
          bottomNavigationBar: TabBar(
            labelColor: Colors.black,
            tabs: [
              Tab(text: 'A'),
              Tab(text: 'B'),
              Tab(text: 'C')
            ]
          ),
        )
      )
    );
  }
}"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s">'package:flutter/material.dart'</span>;

<span class="pl-k">void</span> <span class="pl-en">main</span>() <span class="pl-k">=&gt;</span> <span class="pl-en">runApp</span>(<span class="pl-c1">MyApp</span>());

<span class="pl-k">class</span> <span class="pl-c1">MyApp</span> <span class="pl-k">extends</span> <span class="pl-c1">StatelessWidget</span> {

  <span class="pl-c">// This widget is the root of your application.</span>
  <span class="pl-k">@override</span>
  <span class="pl-c1">Widget</span> <span class="pl-en">build</span>(<span class="pl-c1">BuildContext</span> context) {
    <span class="pl-k">return</span> <span class="pl-c1">MaterialApp</span>(
      title<span class="pl-k">:</span> <span class="pl-s">'Flutter Demo'</span>,
      theme<span class="pl-k">:</span> <span class="pl-c1">ThemeData</span>(
        primarySwatch<span class="pl-k">:</span> <span class="pl-c1">Colors</span>.blue,
      ),
      home<span class="pl-k">:</span> <span class="pl-c1">MyHomePage</span>(title<span class="pl-k">:</span> <span class="pl-s">'Flutter Demo Home Page'</span>),
    );
  }
}

<span class="pl-k">class</span> <span class="pl-c1">MyHomePage</span> <span class="pl-k">extends</span> <span class="pl-c1">StatefulWidget</span> {
  <span class="pl-c1">MyHomePage</span>({<span class="pl-c1">Key</span> key, <span class="pl-c1">this</span>.title}) <span class="pl-k">:</span> <span class="pl-c1">super</span>(key<span class="pl-k">:</span> key);
  <span class="pl-k">final</span> <span class="pl-c1">String</span> title;

  <span class="pl-k">@override</span>
  <span class="pl-c1">_MyHomePageState</span> <span class="pl-en">createState</span>() <span class="pl-k">=&gt;</span> <span class="pl-c1">_MyHomePageState</span>();
}

<span class="pl-k">class</span> <span class="pl-c1">_MyHomePageState</span> <span class="pl-k">extends</span> <span class="pl-c1">State</span>&lt;<span class="pl-c1">MyHomePage</span>&gt; {
  <span class="pl-c1">GlobalKey</span> globalKeyA <span class="pl-k">=</span> <span class="pl-c1">GlobalKey</span>(debugLabel<span class="pl-k">:</span> <span class="pl-s">'A'</span>);

  <span class="pl-k">@override</span>
  <span class="pl-c1">Widget</span> <span class="pl-en">build</span>(<span class="pl-c1">BuildContext</span> context) {
    <span class="pl-k">return</span> <span class="pl-c1">SafeArea</span>(
      child<span class="pl-k">:</span> <span class="pl-c1">DefaultTabController</span>(
        length<span class="pl-k">:</span> <span class="pl-c1">3</span>,
        child<span class="pl-k">:</span> <span class="pl-c1">Scaffold</span>(
          appBar<span class="pl-k">:</span> <span class="pl-c1">AppBar</span>(
            title<span class="pl-k">:</span> <span class="pl-c1">Text</span>(widget.title),
          ),
          body<span class="pl-k">:</span> <span class="pl-c1">TabBarView</span>(
            children<span class="pl-k">:</span> [
              <span class="pl-c1">Navigator</span>(
                key<span class="pl-k">:</span> globalKeyA,
                onGenerateRoute<span class="pl-k">:</span> (_) <span class="pl-k">=&gt;</span> 
                  <span class="pl-c1">MaterialPageRoute</span>(
                    settings<span class="pl-k">:</span> <span class="pl-c1">RouteSettings</span>(
                      isInitialRoute<span class="pl-k">:</span> <span class="pl-c1">true</span>
                    ),
                    builder<span class="pl-k">:</span> (context) <span class="pl-k">=&gt;</span> <span class="pl-c1">Text</span>(<span class="pl-s">'Page A'</span>),
                  )
              ),
              <span class="pl-c1">Text</span>(<span class="pl-s">'Page B'</span>),
              <span class="pl-c1">Text</span>(<span class="pl-s">'Page C'</span>),

            ]
          ),
          bottomNavigationBar<span class="pl-k">:</span> <span class="pl-c1">TabBar</span>(
            labelColor<span class="pl-k">:</span> <span class="pl-c1">Colors</span>.black,
            tabs<span class="pl-k">:</span> [
              <span class="pl-c1">Tab</span>(text<span class="pl-k">:</span> <span class="pl-s">'A'</span>),
              <span class="pl-c1">Tab</span>(text<span class="pl-k">:</span> <span class="pl-s">'B'</span>),
              <span class="pl-c1">Tab</span>(text<span class="pl-k">:</span> <span class="pl-s">'C'</span>)
            ]
          ),
        )
      )
    );
  }
}</pre></div>
<p dir="auto">The error is:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="flutter: #2      Element.updateChild.&lt;anonymous closure&gt; (package:flutter/src/widgets/framework.dart:2724:13)
flutter: #3      Element.updateChild (package:flutter/src/widgets/framework.dart:2727:6)
flutter: #4      SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4838:14)
flutter: #5      Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14)
flutter: #6      Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12)
flutter: #7      SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4838:14)
(etc...)"><pre class="notranslate"><code class="notranslate">flutter: #2      Element.updateChild.&lt;anonymous closure&gt; (package:flutter/src/widgets/framework.dart:2724:13)
flutter: #3      Element.updateChild (package:flutter/src/widgets/framework.dart:2727:6)
flutter: #4      SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4838:14)
flutter: #5      Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14)
flutter: #6      Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12)
flutter: #7      SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4838:14)
(etc...)
</code></pre></div>
<p dir="auto">The problem is that in <code class="notranslate">Element.updateChild</code>, the code checks that a <code class="notranslate">GlobalKey</code> is not being reused by a different widget. But this check occurs before the old child widget has had a chance to be deactivated, so it is unsurprising that the <code class="notranslate">GlobalKey</code> appears to be used twice.</p>
<p dir="auto">This will always happen when an Element that uses a <code class="notranslate">GlobalKey</code> has updateChild called.</p>
<p dir="auto">The fix would be to move the assertion that checks that the <code class="notranslate">GlobalKey</code> is not reused to be later in the <code class="notranslate">updateChild</code> method, after the original has been deactivated.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -2705,18 +2705,12 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
   /// |  **child != null**  |  Old child is removed, returns null. | Old child updated if possible, returns child or new [Element]. |
   @protected
   Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
-    assert(() {
-      if (newWidget != null &amp;&amp; newWidget.key is GlobalKey) {
-        final GlobalKey key = newWidget.key;
-        key._debugReserveFor(this);
-      }
-      return true;
-    }());
     if (newWidget == null) {
       if (child != null)
         deactivateChild(child);
       return null;
     }
+
     if (child != null) {
       if (child.widget == newWidget) {
         if (child.slot != newSlot)
@@ -2737,6 +2731,13 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
       deactivateChild(child);
       assert(child._parent == null);
     }
+    assert(() {
+      if (newWidget.key is GlobalKey) {
+        final GlobalKey key = newWidget.key;
+        key._debugReserveFor(this);
+      }
+      return true;
+    }());
     return inflateWidget(newWidget, newSlot);
   }"><pre class="notranslate"><code class="notranslate">--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -2705,18 +2705,12 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
   /// |  **child != null**  |  Old child is removed, returns null. | Old child updated if possible, returns child or new [Element]. |
   @protected
   Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
-    assert(() {
-      if (newWidget != null &amp;&amp; newWidget.key is GlobalKey) {
-        final GlobalKey key = newWidget.key;
-        key._debugReserveFor(this);
-      }
-      return true;
-    }());
     if (newWidget == null) {
       if (child != null)
         deactivateChild(child);
       return null;
     }
+
     if (child != null) {
       if (child.widget == newWidget) {
         if (child.slot != newSlot)
@@ -2737,6 +2731,13 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
       deactivateChild(child);
       assert(child._parent == null);
     }
+    assert(() {
+      if (newWidget.key is GlobalKey) {
+        final GlobalKey key = newWidget.key;
+        key._debugReserveFor(this);
+      }
+      return true;
+    }());
     return inflateWidget(newWidget, newSlot);
   }
</code></pre></div>
<p dir="auto">It's okay to move the assert to the end, because it cannot possibly trigger on the other code paths.<br>
Either newWidget == null, so it can't have a GlobalKey anyway. Or child.widget == newWidget so the GlobalKey is already being used by the child. Or (see code below), Widget.canUpdate(child.widget, newWidget) is true, which means that child.widget.key == newWidget.key, according to the rules of being allowed to replace a widget.</p>
<div class="highlight highlight-source-dart notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="      if (Widget.canUpdate(child.widget, newWidget)) {
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        child.update(newWidget);
        assert(child.widget == newWidget);
        assert(() {
          child.owner._debugElementWasRebuilt(child);
          return true;
        }());
        return child;
      }"><pre class="notranslate">      <span class="pl-k">if</span> (<span class="pl-c1">Widget</span>.<span class="pl-en">canUpdate</span>(child.widget, newWidget)) {
        <span class="pl-k">if</span> (child.slot <span class="pl-k">!=</span> newSlot)
          <span class="pl-en">updateSlotForChild</span>(child, newSlot);
        child.<span class="pl-en">update</span>(newWidget);
        <span class="pl-k">assert</span>(child.widget <span class="pl-k">==</span> newWidget);
        <span class="pl-k">assert</span>(() {
          child.owner.<span class="pl-en">_debugElementWasRebuilt</span>(child);
          <span class="pl-k">return</span> <span class="pl-c1">true</span>;
        }());
        <span class="pl-k">return</span> child;
      }</pre></div>
<p dir="auto">Therefore, the only place that needs to have the assert to check we're not using a GlobalKey more than once, is near the end of this method.</p>
<p dir="auto">See also:</p>
<p dir="auto"><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="314771757" data-permission-text="Title is private" data-url="https://github.com/flutter/flutter/issues/16630" data-hovercard-type="issue" data-hovercard-url="/flutter/flutter/issues/16630/hovercard" href="https://github.com/flutter/flutter/issues/16630">#16630</a><br>
<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="358514166" data-permission-text="Title is private" data-url="https://github.com/flutter/flutter/issues/21630" data-hovercard-type="issue" data-hovercard-url="/flutter/flutter/issues/21630/hovercard" href="https://github.com/flutter/flutter/issues/21630">#21630</a><br>
<a href="https://stackoverflow.com/questions/49862572/multiple-widgets-used-the-same-globalkey?rq=1" rel="nofollow">https://stackoverflow.com/questions/49862572/multiple-widgets-used-the-same-globalkey?rq=1</a></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ flutter doctor -v
[✓] Flutter (Channel master, v0.11.10-pre.2, on Mac OS X 10.13.6 17G3025, locale en-GB)
    • Flutter version 0.11.10-pre.2 at /Users/steve/code/flutter
    • Framework revision b55e52c6f7 (18 hours ago), 2018-11-21 15:48:23 -0500
    • Engine revision 1e37b99ac0
    • Dart version 2.1.0 (build 2.1.0-dev.9.4 f9ebf21297)

[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
    • Android SDK at /Users/steve/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.1
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
    • All Android licenses accepted.

[!] iOS toolchain - develop for iOS devices (Xcode 10.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.1, Build version 10B61
    ✗ Verify that all connected devices have been paired with this computer in Xcode.
      If all devices have been paired, libimobiledevice and ideviceinstaller may require updating.
      To update with Brew, run:
        brew update
        brew uninstall --ignore-dependencies libimobiledevice
        brew uninstall --ignore-dependencies usbmuxd
        brew install --HEAD usbmuxd
        brew unlink usbmuxd
        brew link usbmuxd
        brew install --HEAD libimobiledevice
        brew install ideviceinstaller
    • ios-deploy 2.0.0
    • CocoaPods version 1.5.3

[✓] Android Studio (version 3.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 26.0.1
    • Dart plugin version 173.4700
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)

[✓] VS Code (version 1.29.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 2.20.0

[✓] Connected device (1 available)
    • iPhone XR • 1EE1625B-61BB-421E-B104-CB3C8A5B6076 • ios • iOS 12.1 (simulator)

! Doctor found issues in 1 category."><pre class="notranslate"><code class="notranslate">$ flutter doctor -v
[✓] Flutter (Channel master, v0.11.10-pre.2, on Mac OS X 10.13.6 17G3025, locale en-GB)
    • Flutter version 0.11.10-pre.2 at /Users/steve/code/flutter
    • Framework revision b55e52c6f7 (18 hours ago), 2018-11-21 15:48:23 -0500
    • Engine revision 1e37b99ac0
    • Dart version 2.1.0 (build 2.1.0-dev.9.4 f9ebf21297)

[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
    • Android SDK at /Users/steve/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.1
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
    • All Android licenses accepted.

[!] iOS toolchain - develop for iOS devices (Xcode 10.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.1, Build version 10B61
    ✗ Verify that all connected devices have been paired with this computer in Xcode.
      If all devices have been paired, libimobiledevice and ideviceinstaller may require updating.
      To update with Brew, run:
        brew update
        brew uninstall --ignore-dependencies libimobiledevice
        brew uninstall --ignore-dependencies usbmuxd
        brew install --HEAD usbmuxd
        brew unlink usbmuxd
        brew link usbmuxd
        brew install --HEAD libimobiledevice
        brew install ideviceinstaller
    • ios-deploy 2.0.0
    • CocoaPods version 1.5.3

[✓] Android Studio (version 3.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 26.0.1
    • Dart plugin version 173.4700
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)

[✓] VS Code (version 1.29.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 2.20.0

[✓] Connected device (1 available)
    • iPhone XR • 1EE1625B-61BB-421E-B104-CB3C8A5B6076 • ios • iOS 12.1 (simulator)

! Doctor found issues in 1 category.
</code></pre></div>
<h2 dir="auto">Steps to Reproduce</h2>
<ol dir="auto">
<li>cd <code class="notranslate">/examples/hello_world/</code></li>
<li>connect a physical Android device</li>
<li><code class="notranslate">flutter run</code></li>
</ol>
<p dir="auto">Output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="mit-macbookpro2:hello_world mit$ flutter run -d 00ca05b380789730
Launching lib/main.dart on Nexus 5X in debug mode...
Exception from flutter run: FormatException: Bad UTF-8 encoding 0xff
dart:isolate  _RawReceivePortImpl._handleMessage

Building APK in debug mode (android-arm)...         5081ms
Installing build/app.apk...                         2435ms
Syncing files to device...                          3968ms"><pre class="notranslate"><code class="notranslate">mit-macbookpro2:hello_world mit$ flutter run -d 00ca05b380789730
Launching lib/main.dart on Nexus 5X in debug mode...
Exception from flutter run: FormatException: Bad UTF-8 encoding 0xff
dart:isolate  _RawReceivePortImpl._handleMessage

Building APK in debug mode (android-arm)...         5081ms
Installing build/app.apk...                         2435ms
Syncing files to device...                          3968ms
</code></pre></div>
<p dir="auto">Running on an Android or iOS simulator does not throw the exception!</p>
<h2 dir="auto">Flutter Doctor</h2>
<p dir="auto">Paste the output of running <code class="notranslate">flutter doctor</code> here.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ flutter doctor
[✓] Flutter (on Mac OS, channel master)
    • Flutter at /Users/mit/dev/github/flutter
    • Framework revision 3a43fc88b6 (5 hours ago), 2017-01-31 23:32:10
    • Engine revision 2d54edf0f9
    • Tools Dart version 1.22.0-dev.9.1

[✓] Android toolchain - develop for Android devices (Android SDK 25.0.0)
    • Android SDK at /Users/mit/Library/Android/sdk
    • Platform android-25, build-tools 25.0.0
    • ANDROID_HOME = /Users/mit/Library/Android/sdk
    • Java(TM) SE Runtime Environment (build 1.8.0_112-b16)

[✓] iOS toolchain - develop for iOS devices (Xcode 8.2.1)
    • XCode at /Applications/Xcode.app/Contents/Developer
    • Xcode 8.2.1, Build version 8C1002

[✓] IntelliJ IDEA Ultimate Edition (version 2016.3.4)
    • Dart plugin version 163.12753
    • Flutter plugin version 0.1.8.1

[✓] Connected devices
    • Nexus 5X                  • 00ca05b380789730 • android-arm • Android 7.0 (API 24)
    • Android SDK built for x86 • emulator-5554    • android-x86 • Android 6.0 (API 23) (emulator)
$"><pre class="notranslate"><code class="notranslate">$ flutter doctor
[✓] Flutter (on Mac OS, channel master)
    • Flutter at /Users/mit/dev/github/flutter
    • Framework revision 3a43fc88b6 (5 hours ago), 2017-01-31 23:32:10
    • Engine revision 2d54edf0f9
    • Tools Dart version 1.22.0-dev.9.1

[✓] Android toolchain - develop for Android devices (Android SDK 25.0.0)
    • Android SDK at /Users/mit/Library/Android/sdk
    • Platform android-25, build-tools 25.0.0
    • ANDROID_HOME = /Users/mit/Library/Android/sdk
    • Java(TM) SE Runtime Environment (build 1.8.0_112-b16)

[✓] iOS toolchain - develop for iOS devices (Xcode 8.2.1)
    • XCode at /Applications/Xcode.app/Contents/Developer
    • Xcode 8.2.1, Build version 8C1002

[✓] IntelliJ IDEA Ultimate Edition (version 2016.3.4)
    • Dart plugin version 163.12753
    • Flutter plugin version 0.1.8.1

[✓] Connected devices
    • Nexus 5X                  • 00ca05b380789730 • android-arm • Android 7.0 (API 24)
    • Android SDK built for x86 • emulator-5554    • android-x86 • Android 6.0 (API 23) (emulator)
$
</code></pre></div>