1

This simple app works fine in debug mode but not release mode:

main.dart:

import 'package:flutter/material.dart';

void main() {

  ErrorWidget.builder = (FlutterErrorDetails details) {
    bool inDebug = false;
    assert(() { inDebug = true; return true; }());
    // In debug mode, use the normal error widget which shows
    // the error message:
    if (inDebug)
      return ErrorWidget(details.exception);
    // In release builds, show a yellow-on-blue message instead:
    return Container(
      alignment: Alignment.center,
      child: Text(
       'Error! ${details.exception} ${details.stack}',
        style: TextStyle(color: Colors.red),
        textDirection: TextDirection.ltr,
      ),
    );
  };

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyWidget(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Builder(
        builder: (context) {
          var list = <int>[1,2,3,4];
          List<int?> nullable = list.sublist(2); // also try "nullable = list"
          nullable.add(null);

          return Center(
            child: Text("nullable $nullable list $list")
          );
        }
      )
    );
  }
}

Have a look at this snippet:

List<int> list = [1,2,3,4];
List<int?> nullable = list.sublist(2);
nullable.add(null);
print("nullable $nullable list $list");

It prints "nullable [3, 4, null] list [1, 2, 3, 4]"

When you change the code to:

List<int> list = [1,2,3,4];
List<int?> nullable = list;
nullable.add(null);
print("nullable $nullable list $list");

It prints: "nullable [1, 2, 3, 4, null] list [1, 2, 3, 4, null]"

So, in the first example it works as I'd expect. But in Flutter it works like that only in the debug mode. When I create an apk in release mode it throws an exception (Null is not a subtype of 'int').

The second example might be understandable too, but it might be unexpected that we end up with a variable which should allow nulls, but when you try to add a null it throws an error.

So, my question here is why does the debug mode in Flutter work like that and can we somehow change it so that it behaves just like in the release mode.

I'm using VS Code, Flutter 3.7.0

1 Answer 1

0

When I run your provided code, I observe the same exception in both debug and release modes.

It appears visually different due to your implementation of ErrorWidget.build, but it is the same exception.

It is expected that this behavior would not differ between debug and release modes.

I suspect the exception is happening for you in debug mode, but it is masked or hidden for some reason. You could try

  • Check the debug console
  • Put a breakpoint in the ErrorWidget builder and/or step over the nullable.add(null) in the debugger
  • Add a print statement after nullable.add(null) to see if it really is proceeding beyond that call

(Side note: You can use the kDebugMode constant to determine debug mode.)

Sign up to request clarification or add additional context in comments.

2 Comments

It turned out that my VS Code config had the option --no-sound-null-safety for debug builds and it caused the problem. Your answer didn't help directly, but still it encouraged me to look for the problem in my dev environment. Thanks.
@wanson Wow that is subtle. Nice find!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.