Skip to content

Flutter and Dart errorFlutter: “type 'Null' is not a subtype of type 'String'”

The app shows a red error screen, or a list stays empty, and the log says type 'Null' is not a subtype of type 'String', often followed by in type cast. Dart expected a String and got null. It almost always comes from data: a JSON field the API did not send, a Firestore document without that field, or route arguments that were never passed. The same message with 'int' or '_Map<String, dynamic>' in place of Null means the value was there, but of a different type.

Short answer

Open the first stack trace line in your own code. It is usually a fromJson factory or a line that reads data['field'], and that field was missing or null. Check the key’s spelling against the real response, then make the field nullable (String?) or give it a default: json['name'] as String? ?? ''. If the message names another type, such as 'int' is not a subtype of type 'String', convert the value (json['id'].toString()) or change the model to match what the API sends.

Where the wrong value comes from, and the fix

  1. 01

    A JSON field that is missing or null

    “If you have a typo when accessing a nonexistent JSON field, your code throws an error during runtime.” Flutter, JSON and serialization

    jsonDecode() returns dynamic, so the compiler can’t see that json['name'] might be null. Assigning it to a String field, or casting it with as String, fails at runtime. A typo in the key gives the same error, because a missing key reads as null.

    // throws when name is missing or null
    name: json['name'] as String,
    
    // handles it
    name: json['name'] as String? ?? '',
  2. 02

    A generated model that is stricter than the data

    With json_serializable or freezed, a field declared as String makes the generated fromJson cast it with as String. Regenerate after changing the model, and declare fields the API can leave out as String?, or give them a default with @JsonKey(defaultValue: '').

  3. 03

    A Firestore document without the field

    “The index [] operator on the Map class returns null if the key isn't present.” Dart, Understanding null safety

    doc.data()!['title'] is null for any document written before the field existed, or written by a code path that skips it. Old documents are the usual reason it fails for some users and not others. Read the field as nullable with a fallback, or add the field to the old documents.

    final data = doc.data()!;
    final title = data['title'] as String? ?? 'Untitled';
  4. 04

    The value is there, but it is a different type

    “If you aren't sure that the object is of type T, then use is T to check the type before using the object.” Dart, Operators: type test operators

    type 'int' is not a subtype of type 'String' means the API sent 42 where the model expects '42'. '_Map<String, dynamic>' is not a subtype of type 'List<dynamic>' means it sent one object where the code expects a list. Check the type with is before using the value, or change the model to match the real response.

    final idText = json['id'].toString(); // 42 or '42' both work
    final tags = json['tags'] is List ? json['tags'] as List : const [];
  5. 05

    Route arguments that were not passed

    “Use the as operator to cast an object to a particular type if and only if you are sure that the object is of that type.” Dart, Operators: type test operators

    ModalRoute.of(context)!.settings.arguments as String is a cast, and it throws on null when a screen opens without arguments, for example from a deep link or a pushNamed call that leaves them out. Read them as String? and handle null, or pass the value through the screen’s constructor instead.

Checked against the vendor’s docs on : Flutter: JSON and serialization; Dart: Operators (type test operators); Dart: Understanding null safety (Map lookups); Dart API: TypeError class.

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: Flutter “Null check operator used on a null value” · Flutter LateInitializationError · Dart “Bad state: No element” · Flutter “Looking up a deactivated widget’s ancestor is unsafe”

Questions

More on this error

Why does it fail for some users and not for me?

Their data is different: older records, accounts without an optional field, or a different API version. Log the raw JSON for the failing screen, or open the document in the Firebase console, and compare it with the model.

Should I make every field nullable?

No. Make a field nullable when the API or the database can leave it out. Keep required fields non-nullable, and fail with a clear message in fromJson, so a broken response is caught in one place instead of on a screen.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.