Deep Analysis and Solutions for JSON Parsing Error: '_InternalLinkedHashMap<String, dynamic>' is not a subtype of 'List<dynamic>' in Flutter

Nov 21, 2025 · Programming · 20 views · 7.8

Keywords: Flutter | JSON Parsing | Type Error | Dart | Data Processing

Abstract: This article provides an in-depth analysis of the common JSON parsing error '_InternalLinkedHashMap<String, dynamic>' is not a subtype of 'List<dynamic>' in Flutter development. Through practical code examples, it explains the differences between JSON arrays and JSON objects, offering solutions for two common scenarios: proper property access when dealing with JSON arrays, and extracting nested list data from JSON objects. The article also covers best practices for type conversion and error handling to help developers avoid such runtime exceptions.

Problem Background and Error Analysis

In Flutter application development, handling JSON data is a common requirement. Many developers encounter type conversion errors when retrieving JSON responses from servers, specifically: Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>'. The core issue here is data type mismatch - the code expects a List but actually receives a Map.

JSON Data Structure Analysis

To understand this error, it's essential to distinguish between the two fundamental JSON structures: arrays and objects. In Dart, JSON arrays are parsed as List<dynamic> types, while JSON objects are parsed as Map<String, dynamic> types. When using the json.decode() method, Dart automatically selects the appropriate type based on the actual JSON structure.

Scenario 1: Proper Handling of JSON Arrays

When the server returns data in JSON array format, the structure typically looks like:

[
    {
        "name": "John",
        "age": 25,
        "email": "john@example.com"
    },
    {
        "name": "Jane",
        "age": 30,
        "email": "jane@example.com"
    }
]

In this case, json.decode(response.body) returns a List<dynamic> object. To access the name property of the first element, the correct approach is:

var data = json.decode(response.body);
print(data[0]["name"]);

It's important to note that you cannot directly use data[0].name because Dart's dynamic types don't automatically convert Map keys to object properties. Unless you perform explicit type casting:

var data = json.decode(response.body).cast<Map<String, dynamic>>();
// Or using custom classes
class User {
    final String name;
    final int age;
    final String email;
    
    User({required this.name, required this.age, required this.email});
    
    factory User.fromJson(Map<String, dynamic> json) {
        return User(
            name: json['name'],
            age: json['age'],
            email: json['email']
        );
    }
}

var users = (json.decode(response.body) as List).map((i) => User.fromJson(i)).toList();
print(users[0].name);

Scenario 2: Handling Nested JSON Objects

Another common scenario is when the server returns a JSON object containing an array:

{
    "status": "success",
    "data": [
        {
            "name": "John",
            "age": 25,
            "email": "john@example.com"
        },
        {
            "name": "Jane",
            "age": 30,
            "email": "jane@example.com"
        }
    ],
    "total": 2
}

In this situation, json.decode(response.body) returns a Map<String, dynamic>, not a List<dynamic>. The correct approach should be:

Map<String, dynamic> responseMap = json.decode(response.body);
List<dynamic> dataList = responseMap["data"];
print(dataList[0]["name"]);

Error Prevention and Best Practices

To avoid such runtime errors, consider adopting the following best practices:

  1. Validate Data Structure in Advance: Check the structure type of the response body before parsing JSON
  2. Use Type-Safe Parsing Methods: Create corresponding data model classes and use fromJson factory methods
  3. Add Error Handling: Use try-catch blocks to catch potential parsing exceptions
  4. Logging for Debugging: Print the complete response body during development to ensure the data structure meets expectations
Future<String> login() async {
    try {
        var response = await http.get(
            Uri.parse("https://etrans.herokuapp.com/test/2"),
            headers: {"Accept": "application/json"}
        );
        
        // Print complete response for debugging
        print('Response body: ${response.body}');
        
        var decodedData = json.decode(response.body);
        
        if (decodedData is List) {
            // Handle array case
            setState(() {
                data = decodedData;
            });
            print(data[0]["name"]);
        } else if (decodedData is Map) {
            // Handle object case
            if (decodedData.containsKey('data') && decodedData['data'] is List) {
                setState(() {
                    data = decodedData['data'];
                });
                print(data[0]["name"]);
            } else {
                throw FormatException('Unexpected JSON structure');
            }
        }
        
        return "Success!";
    } catch (e) {
        print('Error: $e');
        return "Failed: $e";
    }
}

Conclusion

Understanding the correspondence between JSON data structures and Dart's type system is crucial for avoiding such errors. By adopting type-safe parsing methods, adding appropriate error handling, and following best practices, developers can significantly reduce runtime exceptions and improve application stability and maintainability. In practical development, it's recommended to always use explicit data models and type conversions rather than relying on implicit conversions of dynamic types.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.