Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App throws package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true exception upon launch. #89947

Open
mrcsh opened this issue Sep 12, 2021 · 13 comments
Labels
a: error message Error messages from the Flutter framework f: material design flutter/packages/flutter/material repository. found in release: 2.5 Found to occur in 2.5 found in release: 2.6 Found to occur in 2.6 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on team-design Owned by Design Languages team triaged-design Triaged by Design Languages team

Comments

@mrcsh
Copy link

mrcsh commented Sep 12, 2021

We have been seeing this error on the startup of our app for a while. I does not seem to have any impact.
It happens very early on.
With the update to flutter 2.5 the error is more detailed, but still the stack trace does not really indicate where in our code the exception is being thrown from.

full output of flutter run --verbose attached.

Logs
           ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
           The following assertion was thrown building AnimatedTheme(duration: 200ms, dirty, dependencies:
           [_EffectiveTickerMode], state: _AnimatedThemeState#eadb2(ticker active,
           ThemeDataTween(ThemeData#fb5bf → ThemeData#37575))):
           'package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b
           == null || a.inherit == b.inherit': is not true.

           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.md

           The relevant error-causing widget was:
             MaterialApp MaterialApp:file:///nvme/csh/work/secure-mobile/core/lib/application.dart:45:16

           When the exception was thrown, this was the stack:
           #2      TextStyle.lerp (package:flutter/src/painting/text_style.dart:1031:12)
           #3      TextTheme.lerp (package:flutter/src/material/text_theme.dart:432:28)
           #4      Typography.lerp (package:flutter/src/material/typography.dart:289:17)
           #5      ThemeData.lerp (package:flutter/src/material/theme_data.dart:1711:30)
           #6      ThemeDataTween.lerp (package:flutter/src/material/theme.dart:174:41)
           #7      Tween.transform (package:flutter/src/animation/tween.dart:327:12)
           #8      Animatable.evaluate (package:flutter/src/animation/tween.dart:53:46)
           #9      _AnimatedThemeState.build (package:flutter/src/material/theme.dart:230:20)
           #10     StatefulElement.build (package:flutter/src/widgets/framework.dart:4782:27)
           #11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4665:15)
           #12     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4840:11)
           #13     Element.rebuild (package:flutter/src/widgets/framework.dart:4355:5)
           #14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2620:33)
           #15     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
           #16     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:319:5)
           #17     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1143:15)
           #18     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1080:9)
           #19     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
           #23     _invoke (dart:ui/hooks.dart:166:10)
           #24     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
           #25     _drawFrame (dart:ui/hooks.dart:129:31)
           (elided 5 frames from class _AssertionError and dart:async)

           ════════════════════════════════════════════════════════════════════════════════════════════════════

flutter analyze                                                           
The plugins `device_unlock, flutter_app_badger, flutter_incall_manager, flutter_ringtone_player,
flutter_voip_push_notification, image_gallery_saver, proximity_plugin` use a deprecated version of the Android embedding.
To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2
embedding. Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.
If you are plugin author, take a look at the docs for migrating the plugin to the V2 embedding:
https://flutter.dev/go/android-plugin-migration.
Analyzing lochbox...                                                    
No issues found! (ran in 4.3s)

[✓] Flutter (Channel stable, 2.5.0, on Fedora 34 (Thirty Four) 5.13.12-200.fc34.x86_64, locale en_US.UTF-8)
    • Flutter version 2.5.0 at /server/home/csh/lib/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 4cc385b4b8 (4 days ago), 2021-09-07 23:01:49 -0700
    • Engine revision f0826da7ef
    • Dart version 2.14.0

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /home/csh/Android/Sdk
    • Platform android-31, build-tools 30.0.2
    • Java binary at: /server/home/csh/lib/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 12.0.1 (Fedora 12.0.1-1.fc34)
    • cmake version 3.20.5
    • ninja version 1.8.2
    • pkg-config version 1.7.3

[✓] Android Studio (version 2020.3)
    • Android Studio at /server/home/csh/lib/android-studio
    • Flutter plugin version 58.0.2
    • Dart plugin version 203.8292
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)

[✓] VS Code (version 1.60.0)
    • VS Code at /usr/share/code
    • Flutter extension version 3.26.0

[✓] Connected device (6 available)
    • G5 (mobile)                           • 7080018019007106 • android-arm64  • Android 9 (API 28)
    • sdk gphone64 x86 64 (mobile)          • emulator-5554    • android-x64    • Android 11 (API 30) (emulator)
    • Android SDK built for x86 (mobile)    • emulator-5556    • android-x86    • Android 10 (API 29) (emulator)
    • Android SDK built for x86 64 (mobile) • emulator-5558    • android-x64    • Android 9 (API 28) (emulator)
    • Linux (desktop)                       • linux            • linux-x64      • Fedora 34 (Thirty Four)
      5.13.12-200.fc34.x86_64
    • Chrome (web)                          • chrome           • web-javascript • Google Chrome 93.0.4577.63
    ! Device ZY224KQLWQ is not authorized.
      You might need to check your device for an authorization dialog.

• No issues found!
[bug-report.txt](https://github.com/flutter/flutter/files/7150012/bug-report.txt)

@darshankawar darshankawar added the in triage Presently being triaged by the triage team label Sep 13, 2021
@darshankawar
Copy link
Member

@mrcsh
There's similar open issue describing your case, #40514
Please check in your code if setting a custom navigation action text causes this issue or not.

@darshankawar darshankawar added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 13, 2021
@mrcsh
Copy link
Author

mrcsh commented Sep 13, 2021

we are not explicitly setting any custom navActionTextStyle. we are using a theme generated with FlexColorScheme but a quick glance at the code, I didn't see anything in there either.

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 13, 2021
@darshankawar
Copy link
Member

@mrcsh
Is there any chance to provide a replicable and self-contained code sample, that we can use to analyse ?

@darshankawar darshankawar added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 14, 2021
@mrcsh
Copy link
Author

mrcsh commented Sep 14, 2021

I will see what I can do. I don't know what parts of our code need to be isolated. Is is pretty likely that the issue is something with the way the ThemeData has been setup?

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 14, 2021
@mrcsh
Copy link
Author

mrcsh commented Sep 14, 2021 via email

@mrcsh
Copy link
Author

mrcsh commented Sep 14, 2021

bug_lerp_assert.tar.gz

I kept adding stuff until I was able to reproduce it. It seems to happen when the theme is updated from the default.
We have bloc controlling the theme for simplicity I just used a StreamBuilder...

@darshankawar
Copy link
Member

Thanks for the effort to isolate the issue and providing a minimal code sample. I see the same exception on latest master and stable upon app launch.

console error log
======== Exception caught by widgets library =======================================================
The following assertion was thrown building AnimatedTheme(duration: 200ms, dirty, state: _AnimatedThemeState#57a37(ticker active, ThemeDataTween(ThemeData#6500e → ThemeData#60fad))):
'package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true.


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.md

The relevant error-causing widget was: 
  MaterialApp MaterialApp:file:///Users/dhs/Downloads/bug_lerp_assert/lib/main.dart:67:18
When the exception was thrown, this was the stack: 
#2      TextStyle.lerp (package:flutter/src/painting/text_style.dart:1031:12)
#3      TextTheme.lerp (package:flutter/src/material/text_theme.dart:432:28)
#4      Typography.lerp (package:flutter/src/material/typography.dart:289:17)
#5      ThemeData.lerp (package:flutter/src/material/theme_data.dart:1741:30)
#6      ThemeDataTween.lerp (package:flutter/src/material/theme.dart:174:41)
#7      Tween.transform (package:flutter/src/animation/tween.dart:327:12)
#8      Animatable.evaluate (package:flutter/src/animation/tween.dart:53:46)
#9      _AnimatedThemeState.build (package:flutter/src/material/theme.dart:230:20)
#10     StatefulElement.build (package:flutter/src/widgets/framework.dart:4700:27)
#11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4583:15)
#12     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4758:11)
#13     Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)
#15     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#16     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:319:5)
#17     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1148:15)
#18     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1084:9)
#19     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#23     _invoke (dart:ui/hooks.dart:166:10)
#24     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#25     _drawFrame (dart:ui/hooks.dart:129:31)
(elided 5 frames from class _AssertionError and dart:async)
====================================================================================================

======== Exception caught by widgets library =======================================================
The following assertion was thrown building AnimatedTheme(duration: 200ms, dirty, state: _AnimatedThemeState#57a37(ticker active, ThemeDataTween(ThemeData#6500e → ThemeData#60fad))):
'package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true.


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.md

The relevant error-causing widget was: 
  MaterialApp MaterialApp:file:///Users/dhs/Downloads/bug_lerp_assert/lib/main.dart:67:18
When the exception was thrown, this was the stack: 
#2      TextStyle.lerp (package:flutter/src/painting/text_style.dart:1031:12)
#3      TextTheme.lerp (package:flutter/src/material/text_theme.dart:432:28)
#4      Typography.lerp (package:flutter/src/material/typography.dart:289:17)
#5      ThemeData.lerp (package:flutter/src/material/theme_data.dart:1741:30)
#6      ThemeDataTween.lerp (package:flutter/src/material/theme.dart:174:41)
#7      Tween.transform (package:flutter/src/animation/tween.dart:327:12)
#8      Animatable.evaluate (package:flutter/src/animation/tween.dart:53:46)
#9      _AnimatedThemeState.build (package:flutter/src/material/theme.dart:230:20)
#10     StatefulElement.build (package:flutter/src/widgets/framework.dart:4700:27)
#11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4583:15)
#12     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4758:11)
#13     Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)
#15     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#16     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:319:5)
#17     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1148:15)
#18     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1084:9)
#19     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#23     _invoke (dart:ui/hooks.dart:166:10)
#24     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#25     _drawFrame (dart:ui/hooks.dart:129:31)
(elided 5 frames from class _AssertionError and dart:async)
====================================================================================================

======== Exception caught by widgets library =======================================================
The following assertion was thrown building AnimatedTheme(duration: 200ms, dirty, state: _AnimatedThemeState#57a37(ticker active, ThemeDataTween(ThemeData#6500e → ThemeData#60fad))):
'package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true.


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.md

The relevant error-causing widget was: 
  MaterialApp MaterialApp:file:///Users/dhs/Downloads/bug_lerp_assert/lib/main.dart:67:18
When the exception was thrown, this was the stack: 
#2      TextStyle.lerp (package:flutter/src/painting/text_style.dart:1031:12)
#3      TextTheme.lerp (package:flutter/src/material/text_theme.dart:432:28)
#4      Typography.lerp (package:flutter/src/material/typography.dart:289:17)
#5      ThemeData.lerp (package:flutter/src/material/theme_data.dart:1741:30)
#6      ThemeDataTween.lerp (package:flutter/src/material/theme.dart:174:41)
#7      Tween.transform (package:flutter/src/animation/tween.dart:327:12)
#8      Animatable.evaluate (package:flutter/src/animation/tween.dart:53:46)
#9      _AnimatedThemeState.build (package:flutter/src/material/theme.dart:230:20)
#10     StatefulElement.build (package:flutter/src/widgets/framework.dart:4700:27)
#11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4583:15)
#12     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4758:11)
#13     Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)
#15     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#16     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:319:5)
#17     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1148:15)
#18     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1084:9)
#19     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#23     _invoke (dart:ui/hooks.dart:166:10)
#24     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#25     _drawFrame (dart:ui/hooks.dart:129:31)
(elided 5 frames from class _AssertionError and dart:async)
====================================================================================================

stable, master flutter doctor -v
[✓] Flutter (Channel stable, 2.5.0, on Mac OS X 10.15.4 19E2269 darwin-x64,
    locale en-GB)
    • Flutter version 2.5.0 at /Users/dhs/documents/fluttersdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 4cc385b4b8 (2 days ago), 2021-09-07 23:01:49 -0700
    • Engine revision f0826da7ef
    • Dart version 2.14.0

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.3, Build version 12C33
    • CocoaPods version 1.10.1

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

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

[✓] Connected device (3 available)
    • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729 • ios
      • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
    • macOS (desktop)            • macos                                •
      darwin-x64     • Mac OS X 10.15.4 19E2269 darwin-x64
    • Chrome (web)               • chrome                               •
      web-javascript • Google Chrome 93.0.4577.63

• No issues found!

[✓] Flutter (Channel master, 2.6.0-6.0.pre.94, on Mac OS X 10.15.4 19E2269
    darwin-x64, locale en-GB)
    • Flutter version 2.6.0-6.0.pre.94 at
      /Users/dhs/documents/fluttersdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ec61450030 (6 hours ago), 2021-09-14 19:12:05 -0400
    • Engine revision abb1980f65
    • Dart version 2.15.0 (build 2.15.0-96.0.dev)

[✓] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.1

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

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

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-x64     • Mac OS X 10.15.4 19E2269
      darwin-x64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 93.0.4577.63

• No issues found!




@darshankawar darshankawar added f: material design flutter/packages/flutter/material repository. found in release: 2.5 Found to occur in 2.5 found in release: 2.6 Found to occur in 2.6 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on a: error message Error messages from the Flutter framework and removed in triage Presently being triaged by the triage team labels Sep 15, 2021
@darshankawar darshankawar changed the title Exception on application startup. App throws package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true exception upon launch. Sep 15, 2021
@darshankawar
Copy link
Member

/cc: @HansMuller

@rydmike
Copy link
Contributor

rydmike commented Sep 15, 2021

@mrcsh This error looks very similar to what happens if you change ThemeData in a MaterialApp and the new ThemeData object uses different Typography.

Since you mentioned FlexColorScheme (I'm the author of it) above, this might happen if you eg use a light theme based on it and dark theme made with standard methods, or wise versa, or just try to lerp between any two general ThemeData with different Typography. When you give a MaterialApp a new ThemeData object, it automatically animates between them using lerp.

FlexColorScheme defaults to the newer, according to Material Guide, correct Typography.material2018 whereas Flutter SDK default ThemeData() and ThemeData.from() factories still by default use the old Typography.material2014. Why Flutter SDK has not switch yet is a bit long in the tooth, but yeah backwards compatibility I assume. I was hoping to see the new one in Flutter 2.5 as default, but it is not so yet, not even on master.

For some more info on this issue see here: rydmike/flex_color_scheme#9

If you first create a default theme made with ThemeData() or ThemeData.from() and then upgrade that somehow during your app startup process to FlexColorScheme.light().toTheme or FlexColorScheme.dark().toTheme and the default one has already been passed to your MaterialApp, then yes your app will try to lerp between two ThemeData objects that now have different Typography, which Flutter SDK currently cannot do without throwing this error.

In the issue above rydmike/flex_color_scheme#9 I also show how this happens even if you do not use FlexColorScheme, it is enough to just use two different ThemeData with different Typography, which is basically what I suspect is happening in your situation. Without seeing the code it is guess, so I might be wrong, but it looks so.

FlexColorScheme just returns a normal ThemeData object at the end of its definitions, so it is not really any different from doing all the ThemeData definitions it does manually.

You can of course solve this issue by assigning Typography.material2018() to your default ThemeData(typography), then it will also use the same nicer typography as FlexColorScheme and this lerping issue goes away.

By the way, if you are just using a default ThemeData() as some kind of temp interim step at startup, you might not actually need to do that all, you can use the FlexColorScheme based defaults as well eg. FlexColorScheme.light().toTheme work well as a default theme too, especially if your are otherwise using ThemeData based on it.

An even nicer way is to fully form the target ThemeData before applying it at all to your MaterialApp. Then there is never any flash or change of theme during startup, it just uses the right ThemeData from app start, that might have been recalled from local persistence using whatever storage means you prefer. That's what I do and recommend anyway. Next release of FlexColorScheme will include an example with one possible way of doing all this, for those interested in it. It has been requested a lot, so I figured I would just add a more advanced example that shows one possible way of doing it.


@HansMuller Imo lerping between ThemeData with TextStyles based on different Typography should not throw an error. It should just swap the Typographic text styles at the mid animation point, like lerping bools might do. Imo this is OK since it cannot really be expected to animate the Typography changes visually anyway. Yes it will not be a smooth swap, but at least it would not throw. There are probably some legitimate reasons for changing typographic text styles in your MaterialApp's ThemeData dynamically, even if they might be rare, so it should probably not throw an error if you do so.


Typography Sidenote

As a minor side note, I just happened on this issue right now when I was researching status of Typography defaults in 2.5.0 and master, and searching also for issues that mention Typography as a part of that status research, quite a coincidence really that I stumbled in here.

When it comes to my findings from that discovery here is what I learned:

Interestingly Typography() factory itself now defaults to Typography.material2018 as seen here:

class Typography with Diagnosticable {
  /// Creates a typography instance.
  ///
  /// This constructor is identical to [Typography.material2018].
  factory Typography({
    TargetPlatform? platform,
    TextTheme? black,
    TextTheme? white,
    TextTheme? englishLike,
    TextTheme? dense,
    TextTheme? tall,
  }) = Typography.material2018;

This is a pretty new change, from Jun 15, 2021:
image
image

But of course ThemeData() with its elaborate TextTheme creation process still force feeds 2014 via:

    platform ??= defaultTargetPlatform;
    typography ??= Typography.material2014(platform: platform);
    TextTheme defaultTextTheme = isDark ? typography.white : typography.black;
    TextTheme defaultPrimaryTextTheme = primaryIsDark ? typography.white : typography.black;
    TextTheme defaultAccentTextTheme = accentIsDark ? typography.white : typography.black;
    if (fontFamily != null) {
      defaultTextTheme = defaultTextTheme.apply(fontFamily: fontFamily);
      defaultPrimaryTextTheme = defaultPrimaryTextTheme.apply(fontFamily: fontFamily);
      defaultAccentTextTheme = defaultAccentTextTheme.apply(fontFamily: fontFamily);
    }
    textTheme = defaultTextTheme.merge(textTheme);
    primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme);
    accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme);

The Typography.debugFillProperties also defaults to 2014, which matches default TextTheme in ThemeData, but not what the default for Typography() is, but this might also be intentional.

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    final Typography defaultTypography = Typography.material2014();
    properties.add(DiagnosticsProperty<TextTheme>('black', black, defaultValue: defaultTypography.black));
    properties.add(DiagnosticsProperty<TextTheme>('white', white, defaultValue: defaultTypography.white));
    properties.add(DiagnosticsProperty<TextTheme>('englishLike', englishLike, defaultValue: defaultTypography.englishLike));
    properties.add(DiagnosticsProperty<TextTheme>('dense', dense, defaultValue: defaultTypography.dense));
    properties.add(DiagnosticsProperty<TextTheme>('tall', tall, defaultValue: defaultTypography.tall));
  }

@mrcsh
Copy link
Author

mrcsh commented Sep 15, 2021

That is a lot of info, thanks.
Our app starts with a null light and dark ThemeData, and we do pull some settings from local storage and then asynchronously update when we have pulled out the data. So it sounds like if I start with a theme data that has the 2018 typography the issue should go away. We will still have the flash as the theme changes from the default which we can live with for now.

@mrcsh
Copy link
Author

mrcsh commented Sep 16, 2021

So using

Theme.of(context).copyWith(typography: Typeography.material2018()) 

if our theme definition was not available did not work, but using a FlexColorScheme generated ThemeData from our static config and then updating it to a newer version once we loaded the dynamic parts did eliminate the exception, (and the color flash)

@rydmike
Copy link
Contributor

rydmike commented Sep 16, 2021

Correct finding, because if you do a:

Theme.of(context).copyWith(typography: Typography.material2018()) 

You are only creating a copy of ThemeData() with the typography property replaced with the new value using the ThemeData.raw() constructor. Whereas when you create a ThemeData object with the factory ThemeData(typography: Typography.material2018()) it uses passed in Typography to create a TextTheme based on it, with different TextStyles. where the lerp assert issue happens.

So with the above update you did not actually change the differences in typographic text styles that the SDK does not want to lerp between. Only the ThemeData() factory actually includes code to do so, the copyWith() does not call it. Which is why I mentioned that if you are working with ThemeData() directly, you should set in already your current (null) defaults:

ThemeData(typography: Typography.material2018())`

Or if you are using eg ThemeData.light() then replace it with ThemeData(brightness: Brightness.light, typography: Typography.material2018());

It is possible to do it with copyWith as well, but you need to work on the textTheme and merge in the correct typography, something like this, for adding a custom textTheme in light theme mode:

.copyWith(textTheme: ... ).merge(Typography.material2018(platform: defaultTargetPlatform).black),

Messy. There was discussion about it here: rydmike/flex_color_scheme#15

So for next update FlexColorScheme, among other features, I will make using using custom text themes easier, since the proper steps to copy and merge them into ThemeData has many users stumbling (generally in Flutter too, if they don't use the ThemeData factory for it). So for convenience I'm going to bake in the ThemeData textTheme creation steps into it, so a custom defined TextTheme can be added directly without need for a copyWith + merge.


BTW:
The more I look at the Flutter SDK assert that throws this error, the stranger it appears. I'll take a look at again tomorrow with fresh eyes and try to dig into the cause, and see if it is actually even needed, and if so why.

  static TextStyle? lerp(TextStyle? a, TextStyle? b, double t) {
    assert(t != null);
    assert(a == null || b == null || a.inherit == b.inherit);
    if (a == null && b == null) {
      return null;
    }

@rydmike
Copy link
Contributor

rydmike commented Sep 19, 2021

Consider this additional example

Consider this simple Flutter SDK only example where we toggle between two different themes in light and dark mode.
Where light mode uses default Typography.material2014 and dark mode uses Typography.material2018 in accordance to the Material Guide.

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.from(colorScheme: const ColorScheme.light()),
      darkTheme: ThemeData.from(
        colorScheme: const ColorScheme.dark(),
      ).copyWith(typography: Typography.material2018()),
      themeMode: themeMode,
      home: MyHomePage(
        title: 'Flutter Demo Home Page',
        themeMode: themeMode,
        onThemeModeChanged: (ThemeMode mode) {
          setState(() {
            themeMode = mode;
          });
        },
      ),
    );

This will trigger the assert reported in this issue as well.

Assert error: Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true.

The following assertion was thrown building AnimatedTheme(duration: 200ms, dirty, state: _AnimatedThemeState#79c49(ticker active, ThemeDataTween(ThemeData#caa00 → ThemeData#4d489))):
'package:flutter/src/painting/text_style.dart': Failed assertion: line 1031 pos 12: 'a == null || b == null || a.inherit == b.inherit': is not true.


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.md

The relevant error-causing widget was: 
  MaterialApp MaterialApp:file:///C:/Users/mryds/OneDrive/code/flutter/_issues/typography_issue/lib/main.dart:20:12
When the exception was thrown, this was the stack: 
#2      TextStyle.lerp (package:flutter/src/painting/text_style.dart:1031:12)
#3      TextTheme.lerp (package:flutter/src/material/text_theme.dart:432:28)
#4      Typography.lerp (package:flutter/src/material/typography.dart:289:17)
#5      ThemeData.lerp (package:flutter/src/material/theme_data.dart:1741:30)
#6      ThemeDataTween.lerp (package:flutter/src/material/theme.dart:174:41)
#7      Tween.transform (package:flutter/src/animation/tween.dart:327:12)
#8      Animatable.evaluate (package:flutter/src/animation/tween.dart:53:46)
#9      _AnimatedThemeState.build (package:flutter/src/material/theme.dart:230:20)
#10     StatefulElement.build (package:flutter/src/widgets/framework.dart:4700:27)
#11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4583:15)
#12     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4758:11)
#13     Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)
#15     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#16     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:319:5)
#17     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1145:15)
#18     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
#19     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#23     _invoke (dart:ui/hooks.dart:166:10)
#24     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#25     _drawFrame (dart:ui/hooks.dart:129:31)
(elided 5 frames from class _AssertionError and dart:async)

This assert error currently occurs on all Flutter channels.

Illustrated here:

Full sample code

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ThemeMode themeMode = ThemeMode.system;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.from(colorScheme: const ColorScheme.light()),
      darkTheme: ThemeData.from(
        colorScheme: const ColorScheme.dark(),
      ).copyWith(typography: Typography.material2018()),
      themeMode: themeMode,
      home: MyHomePage(
        title: 'Flutter Demo Home Page',
        themeMode: themeMode,
        onThemeModeChanged: (ThemeMode mode) {
          setState(() {
            themeMode = mode;
          });
        },
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({
    Key? key,
    required this.title,
    required this.themeMode,
    required this.onThemeModeChanged,
  }) : super(key: key);

  final String title;
  final ThemeMode themeMode;
  final ValueChanged<ThemeMode> onThemeModeChanged;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Toggle theme to see error'),
            ThemeModeSwitch(
              themeMode: themeMode,
              onChanged: onThemeModeChanged,
            ),
          ],
        ),
      ),
    );
  }
}

/// Widget used to toggle the theme style of the application.
@immutable
class ThemeModeSwitch extends StatelessWidget {
  const ThemeModeSwitch({
    Key? key,
    required this.themeMode,
    required this.onChanged,
  }) : super(key: key);
  final ThemeMode themeMode;
  final ValueChanged<ThemeMode> onChanged;

  @override
  Widget build(BuildContext context) {
    final List<bool> isSelected = <bool>[
      themeMode == ThemeMode.light,
      themeMode == ThemeMode.system,
      themeMode == ThemeMode.dark,
    ];
    return ToggleButtons(
      isSelected: isSelected,
      onPressed: (int newIndex) {
        if (newIndex == 0) {
          onChanged(ThemeMode.light);
        } else if (newIndex == 1) {
          onChanged(ThemeMode.system);
        } else {
          onChanged(ThemeMode.dark);
        }
      },
      children: const <Widget>[
        Icon(Icons.wb_sunny),
        Icon(Icons.phone_iphone),
        Icon(Icons.bedtime),
      ],
    );
  }
}

Why is the assert needed?

Is there any possibility that the assert is a left over from when the different lerping situations in TextStyle were not properly implemented?

If we look at these checks:

  static TextStyle? lerp(TextStyle? a, TextStyle? b, double t) {
    assert(t != null);
    assert(a == null || b == null || a.inherit == b.inherit);
    if (a == null && b == null) {
      return null;
    }

If both a and b are null, obviously do nothing. Later in the lerping cases, it starts with option for when a is null:

    if (a == null) {
      return TextStyle(
        inherit: b!.inherit,
        ...

Then the case for when b is null:

    if (b == null) {
      return TextStyle(
        inherit: a.inherit,
        ...

Then finally the case for when neither is null, only one left since we returned null earlier when both were null:

    return TextStyle(
      inherit: b.inherit,
      color:
        ...

The assert is thrown, because the use case in this issue does not fulfill the a.inherit == b.inherit assertion, which comes from the situation that the following TextStyles in Typography:

  • englishLike2014
  • dense2014
  • tall2014

Set inherit flag to false, all other typography in typography.dart use TextStyle with inherit: true.

Questions:

  • Why do the above 3 typography use TextStyle with inherit set to false?
  • Why is the assert line assert(a == null || b == null || a.inherit == b.inherit); needed?

If the 3 TextStyles above would use inherit: true, the assert would not be triggered in this use case. And of course, if we remove the assert, at least this case runs and works fine, as illustrated below:

Where there is now no assert error shown when toggling between the same themes, and we can also see the slight difference in the typography geometry between the used themes in light and dark mode as well.

Perhaps the assert does fill some other meaningful purpose, I don't have enough insights to know its detailed purpose, but at least in this use case, it is just in the way.

/cc @HansMuller @darshankawar

@flutter-triage-bot flutter-triage-bot bot added team-design Owned by Design Languages team triaged-design Triaged by Design Languages team labels Jul 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: error message Error messages from the Flutter framework f: material design flutter/packages/flutter/material repository. found in release: 2.5 Found to occur in 2.5 found in release: 2.6 Found to occur in 2.6 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on team-design Owned by Design Languages team triaged-design Triaged by Design Languages team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants