Skip to content

TextFormField may throw Exception when deleting text from field with CJK keyboard in a route pushed using CupertinoPageRoute on Android #153003

@horikana

Description

@horikana

Steps to reproduce

  1. Run the sample code on an Android device or emulator (regardless of debug or release mode).
  2. Paste a long string into the TextFormField on a screen navigated to using CupertinoPageRoute.
    When using MaterialPageRoute for navigation, no exception occurs.
  3. With the end of the string visible at the right edge of the TextFormField, select part or all of the text.
  4. Press the Backspace key.

An exception will occur.

Expected results

The expected behavior is that the selected text should be deleted without an exception occurring.

Actual results

When navigating between screens in a MaterialApp, using MaterialPageRoute does not cause any exceptions with TextFormField. However, using CupertinoPageRoute causes an exception with TextFormField.

The exception occurs only when the maxLines property of TextFormField is set to 1. It happens when a long string is pasted into the field, and the text at the right end is visible. If the text is selected (either a range or all text) and the Backspace key is pressed, an exception is thrown. This issue does not occur when cutting, pasting, or entering other characters.

By the way, there were no issues with version 3.19.6. I'm not certain about the exact version, but I believe the issue started occurring with version 3.2x.

Code sample

Code sample
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('TextFormField Test'),
        ),
        body: const Padding(
          padding: EdgeInsets.all(16.0),
          child: MyHome(),
        ),
      ),
    );
  }
}

class MyHome extends StatefulWidget {
  const MyHome({super.key});

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
        TextButton(
          onPressed: () async {
            await Navigator.of(context).push(
              MaterialPageRoute(
                  settings: const RouteSettings(name: '/MyTextTest'),
                  builder: (BuildContext innerContext) => const MyTextTest()),
            );
          },
          child: const Text('push: MaterialPageRoute -- OK'),
        ),
        TextButton(
          onPressed: () async {
            await Navigator.of(context).push(
              CupertinoPageRoute(
                  settings: const RouteSettings(name: '/MyTextTest'),
                  builder: (BuildContext innerContext) => const MyTextTest()),
            );
          },
          child: const Text('push: CupertinoPageRoute -- NG'),
        ),
      ]),
    );
  }
}

class MyTextTest extends StatefulWidget {
  const MyTextTest({super.key});

  @override
  State<MyTextTest> createState() => _MyTextTestState();
}

class _MyTextTestState extends State<MyTextTest> {
  final TextEditingController _urlTextInputController = TextEditingController();

  @override
  void initState() {
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: SafeArea(
        child: Stack(children: <Widget>[
          SingleChildScrollView(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                TextFormField(
                  controller: _urlTextInputController,
                  maxLines: 1,
                  decoration: const InputDecoration(
                    labelText: 'Enter text',
                  ),
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return 'Please enter some text';
                    }
                    return null;
                  },
                ),
              ],
            ),
          ),
        ]),
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]
TextFormField_backspace

Logs

Logs
════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during performLayout():
RenderBox.size accessed beyond the scope of resize, layout, or permitted parent access. RenderBox can always access its own size, otherwise, the only object that is allowed to read RenderBox.size is its parent, if they have said they will. It you hit this assert trying to access a child's size, pass "parentUsesSize: true" to that child's layout() in RenderFractionalTranslation.performLayout.
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2178 pos 16: 'sizeAccessAllowed'

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.yml

The relevant error-causing widget was:
    TextFormField TextFormField:file:///xxxxxx/lib/main.dart:101:17

When the exception was thrown, this was the stack:
#2      RenderBox.size.<anonymous closure> (package:flutter/src/rendering/box.dart:2178:16)
#3      RenderBox.size (package:flutter/src/rendering/box.dart:2199:6)
#4      RenderFractionalTranslation.applyPaintTransform (package:flutter/src/rendering/proxy_box.dart:2952:24)
#5      RenderObject.getTransformTo (package:flutter/src/rendering/object.dart:3411:25)
#6      RenderBox.localToGlobal (package:flutter/src/rendering/box.dart:2887:39)
#7      RenderEditable._snapToPhysicalPixel (package:flutter/src/rendering/editable.dart:2276:33)
#8      RenderEditable.getLocalRectForCaret (package:flutter/src/rendering/editable.dart:1822:28)
#9      EditableTextState._handleContextMenuOnScroll (package:flutter/src/widgets/editable_text.dart:3852:56)
#10     EditableTextState.build.<anonymous closure> (package:flutter/src/widgets/editable_text.dart:5228:21)
#11     _NotificationElement.onNotification (package:flutter/src/widgets/notification_listener.dart:130:38)
#12     _NotificationNode.dispatchNotification (package:flutter/src/widgets/framework.dart:3403:18)
#13     Element.dispatchNotification (package:flutter/src/widgets/framework.dart:5077:24)
#14     Notification.dispatch (package:flutter/src/widgets/notification_listener.dart:60:13)
#15     ScrollActivity.dispatchScrollStartNotification (package:flutter/src/widgets/scroll_activity.dart:99:65)
#16     ScrollPosition.didStartScroll (package:flutter/src/widgets/scroll_position.dart:1027:15)
#17     ScrollPosition.beginActivity (package:flutter/src/widgets/scroll_position.dart:1018:7)
#18     ScrollPositionWithSingleContext.beginActivity (package:flutter/src/widgets/scroll_position_with_single_context.dart:113:11)
#19     ScrollPositionWithSingleContext.goBallistic (package:flutter/src/widgets/scroll_position_with_single_context.dart:146:7)
#20     IdleScrollActivity.applyNewDimensions (package:flutter/src/widgets/scroll_activity.dart:175:14)
#21     ScrollPosition.applyNewDimensions (package:flutter/src/widgets/scroll_position.dart:718:15)
#22     ScrollPositionWithSingleContext.applyNewDimensions (package:flutter/src/widgets/scroll_position_with_single_context.dart:102:11)
#23     ScrollPosition.applyContentDimensions (package:flutter/src/widgets/scroll_position.dart:647:7)
#24     RenderEditable.performLayout (package:flutter/src/rendering/editable.dart:2345:12)
#25     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#26     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#27     _RenderSizeChangedWithCallback.performLayout (package:flutter/src/widgets/size_changed_layout_notifier.dart:90:11)
#28     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#29     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#30     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#31     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#32     RenderLeaderLayer.performLayout (package:flutter/src/rendering/proxy_box.dart:4751:11)
#33     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#34     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#35     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#36     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#37     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#38     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#39     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#40     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#41     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#42     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#43     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#44     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#45     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#46     RenderTapRegion.layout (package:flutter/src/widgets/tap_region.dart:568:11)
#47     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#48     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#49     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#50     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#51     ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:61:11)
#52     _RenderDecoration._layout (package:flutter/src/material/input_decorator.dart:1036:67)
#53     _RenderDecoration.performLayout (package:flutter/src/material/input_decorator.dart:1299:44)
#54     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#55     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#56     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#57     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#58     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#59     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#60     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#61     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#62     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#63     RenderTapRegion.layout (package:flutter/src/widgets/tap_region.dart:568:11)
#64     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#65     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#66     ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:61:11)
#67     RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:985:73)
#68     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1051:32)
#69     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#70     RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:234:12)
#71     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#72     _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:483:14)
#73     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#74     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#75     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#76     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#77     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#78     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#79     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#80     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#81     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#82     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#83     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#84     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#85     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#86     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#87     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#88     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#89     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1448:11)
#90     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#91     ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:61:11)
#92     RenderStack._computeSize (package:flutter/src/rendering/stack.dart:595:43)
#93     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:622:12)
#94     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#95     RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:234:12)
#96     RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#97     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:173:12)
#98     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1092:7)
#99     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:237:7)
#100    RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:404:14)
#101    RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2446:7)
#102    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1052:18)
#103    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1065:15)
#104    RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:602:23)
#105    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1164:13)
#106    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:468:5)
#107    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1397:15)
#108    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1318:9)
#109    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1176:5)
#110    _invoke (dart:ui/hooks.dart:312:13)
#111    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:419:5)
#112    _drawFrame (dart:ui/hooks.dart:283:31)
(elided 2 frames from class _AssertionError)

The following RenderObject was being processed when the exception was fired: RenderEditable#b2357 relayoutBoundary=up31 NEEDS-LAYOUT NEEDS-PAINT
    needs compositing
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=416.0, 0.0<=h<=Infinity)
    size: Size(416.0, 24.0)
    cursorColor: Color(0xff6750a4)
    showCursor: ValueNotifier<bool>#8d4ea(true)
    maxLines: 1
    minLines: null
    selectionColor: Color(0x666750a4)
    locale: en_US
    selection: TextSelection.collapsed(offset: 197, affinity: TextAffinity.downstream, isDirectional: false)
    offset: ScrollPositionWithSingleContext#82945(offset: 1463.3, range: 0.0..1407.2, viewport: 416.0, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics -> ClampingScrollPhysics -> RangeMaintainingScrollPhysics, BallisticScrollActivity#2c9f9(AnimationController#c1116(▶ 1463.333; for BallisticScrollActivity)), ScrollDirection.idle)
    text: TextSpan
        debugLabel: ((englishLike bodyLarge 2021).merge((blackMountainView bodyLarge).apply)).merge(unknown)
        inherit: false
        color: Color(0xff1d1b20)
        family: Roboto
        size: 16.0
        weight: 400
        letterSpacing: 0.5
        baseline: alphabetic
        height: 1.5x
        leadingDistribution: even
        decoration: Color(0xff1d1b20) TextDecoration.none
        "https://www.google.com/search?q=UnmodifiableUint8ListView+flutter&oq=UnmodifiableUint8ListView+flutter&gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIGCAEQRRg8MgYIAhBFGDwyBggDEEUYPNIBCDI4MzhqMGo0qAIAsAIB&sourceid=&ie=UTF-8"
RenderObject: RenderEditable#b2357 relayoutBoundary=up31 NEEDS-LAYOUT NEEDS-PAINT
    needs compositing
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=416.0, 0.0<=h<=Infinity)
    size: Size(416.0, 24.0)
    cursorColor: Color(0xff6750a4)
    showCursor: ValueNotifier<bool>#8d4ea(true)
    maxLines: 1
    minLines: null
    selectionColor: Color(0x666750a4)
    locale: en_US
    selection: TextSelection.collapsed(offset: 197, affinity: TextAffinity.downstream, isDirectional: false)
    offset: ScrollPositionWithSingleContext#82945(offset: 1463.3, range: 0.0..1407.2, viewport: 416.0, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics -> ClampingScrollPhysics -> RangeMaintainingScrollPhysics, BallisticScrollActivity#2c9f9(AnimationController#c1116(▶ 1463.333; for BallisticScrollActivity)), ScrollDirection.idle)
    text: TextSpan
        debugLabel: ((englishLike bodyLarge 2021).merge((blackMountainView bodyLarge).apply)).merge(unknown)
        inherit: false
        color: Color(0xff1d1b20)
        family: Roboto
        size: 16.0
        weight: 400
        letterSpacing: 0.5
        baseline: alphabetic
        height: 1.5x
        leadingDistribution: even
        decoration: Color(0xff1d1b20) TextDecoration.none
        "https://www.google.com/search?q=UnmodifiableUint8ListView+flutter&oq=UnmodifiableUint8ListView+flutter&gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIGCAEQRRg8MgYIAhBFGDwyBggDEEUYPNIBCDI4MzhqMGo0qAIAsAIB&sourceid=&ie=UTF-8"
════════════════════════════════════════════════════════════════════════════════

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.24.0, on Microsoft Windows [Version 10.0.22631.3880], locale ja-JP)
    • Dart version 3.5.0
    • DevTools version 2.37.2
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.4.0)
[√] Android Studio (version 2023.2)
[√] VS Code (version 1.92.0)
[√] Connected device (4 available)
[√] Network resources

• No issues found!

Metadata

Metadata

Labels

P2Important issues not at the top of the work lista: error messageError messages from the Flutter frameworka: internationalizationSupporting other languages or locales. (aka i18n)a: text inputEntering text in a text field or keyboard related problemsc: regressionIt was better in the past than it is nowf: cupertinoflutter/packages/flutter/cupertino repositoryf: routesNavigator, Router, and related APIs.found in release: 3.24Found to occur in 3.24frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyr: fixedIssue is closed as already fixed in a newer versionteam-text-inputOwned by Text Input teamtriaged-text-inputTriaged by Text Input team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions