Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

json_serializable fromJson Error: How to Fix It?

Fix ‘fromJson’ not defined errors in Dart when using json_serializable with nested classes. Learn what steps to take and why these errors happen.
Frustrated developer facing 'fromJson not defined' Dart error with Flutter logos and code generation visuals Frustrated developer facing 'fromJson not defined' Dart error with Flutter logos and code generation visuals
  • ⚠️ The 'fromJson' isn't defined for the type error often comes from missing annotations or code generation.
  • 🧰 Using json_serializable and build_runner correctly handles deserialization automatically and safely.
  • 🧩 Nested classes in Dart need clear annotations and generation to serialize correctly.
  • 📂 Arranging models with their .g.dart files prevents import and generation problems.
  • 🧪 Unit testing .fromJson() methods greatly cuts down on hidden serialization bugs.

Solving the 'fromJson' Isn't Defined Error in Dart

If you get the 'fromJson' isn't defined for the type 'X' error using the json_serializable package in Dart, many others do too. This usually happens with nested models in Flutter apps. It is important to know how Dart’s code generation works then. Let's see why this error shows up, when it happens with nested classes, and how to fix and stop it from happening in your projects.


Understanding json_serializable in Dart

The json_serializable package from the Dart team makes converting between JSON and Dart objects easier. It uses annotations and code generation. For maintenance and growth, this package is key for Flutter apps that handle complicated JSON data.

Important parts of json_serializable are:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  • @JsonSerializable(): Lets the code generator make serialization code for a Dart model.
  • factory Model.fromJson(...): This constructor is made automatically by the code generator.
  • Map<String, dynamic> toJson(): This is the other method, also made automatically.
  • part 'model.g.dart': This links your model's file to the generated code.

All these parts together mean you do not need to write repeated mapping code. They also stop type errors when the app runs and make parsing or converting JSON safer during compilation.

Using json_serializable is extra important when working with big JSON APIs. This is true especially when nested or related data needs to be read correctly. If you use a REST API with nested objects, wrong handling might crash your app when it runs. So, setting this up correctly is a must.


Why fromJson Fails for Nested Classes

A common problem with Dart JSON deserialization is the error: 'fromJson' isn't defined for the type 'X'. This happens most often when you use nested models, where the main class has other class instances as fields.

Dart does not automatically know how to deserialize nested classes. You must tell it how to handle each level of nesting.

Main Reasons for the Error

  • ❌ The nested class does not have the @JsonSerializable() annotation.
  • ❌ The factory constructor fromJson() is missing or not written correctly.
  • part 'nested_model.g.dart'; is not there, so no code is made for that file.
  • build_runner was not run to make the .g.dart files.
  • ❌ Imports for generated files are missing or typed wrong.

What is hard about this error is that it does not always appear during the build. It often shows up when the app is running, or through features that do not work quite right. So, a full setup and knowing the code generation system are very important.


Fixing the Problem Step-by-Step

Let’s go through a clear, sure way to fix this error and avoid it in your code later.

✅ Step 1: Annotate All Classes

Even your nested classes need @JsonSerializable(). Without this, the code generator will skip them. This leads to missing fromJson() and toJson() methods.

import 'package:json_annotation/json_annotation.dart';

part 'address.g.dart';

@JsonSerializable()
class Address {
  final String street;
  final String city;

  Address({required this.street, required this this.city});

  factory Address.fromJson(Map<String, dynamic> json) => _$AddressFromJson(json);
  Map<String, dynamic> toJson() => _$AddressToJson(this);
}

✅ Step 2: Define Both Serialization Methods

Your nested class must have both:

factory Address.fromJson(Map<String, dynamic> json) => _$AddressFromJson(json);
Map<String, dynamic> toJson() => _$AddressToJson(this);

The generated .g.dart file uses these.

✅ Step 3: Include a part Directive

At the top of the file, link your class to its code generation output:

part 'address.g.dart';

If you work with a modular setup, make sure to handle nested structures correctly with part of too.

✅ Step 4: Run the Code Generator

You must run build_runner any time you:

  • Add new classes
  • Change fields
  • Alter annotations

Run this command:

flutter pub run build_runner build

Or in watch mode:

flutter pub run build_runner watch

It is fine to do a clean build first. This removes any broken or partial generations:

flutter pub run build_runner clean
flutter pub run build_runner build --delete-conflicting-outputs

✅ Step 5: Import and Export Correctly

Check that:

  1. You import the file with the fromJson method.
  2. The right generated .g.dart files are in there.
    Good barrel files can help bring exports together (we will talk about this later).

Code Example: A Correctly Serialized Nested Model

To show this process, here is an example using User and Address.

// user.dart
import 'package:json_annotation/json_annotation.dart';
import 'address.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final String name;
  final Address address;

  User({required this.name, required this.address});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}
// address.dart
import 'package:json_annotation/json_annotation.dart';

part 'address.g.dart';

@JsonSerializable()
class Address {
  final String street;
  final String city;

  Address({required this.street, required this.city});

  factory Address.fromJson(Map<String, dynamic> json) => _$AddressFromJson(json);
  Map<String, dynamic> toJson() => _$AddressToJson(this);
}

Common problems that will cause the 'fromJson' isn't defined error:

  • Address.fromJson() not made because of a missing annotation.
  • No part 'address.g.dart' listed.
  • build_runner was never run or failed without a clear message.

Common Mistakes That Cause This Error

Even skilled developers can make these mistakes:

  • ❌ Missing @JsonSerializable() on nested models.
  • ❌ Forgetting fromJson() methods or naming them wrong.
  • ❌ Not listing the part directive.
  • ❌ Filenames for .dart and .g.dart do not match.
  • ❌ Not running build_runner after changes.
  • ❌ Not re-importing .g.dart files after they are rebuilt.
  • ❌ Duplicate or abstract base class without @JsonSerializable().

Dart's code generation system is strict. Every part must be in place.


Best Ways to Arrange Models and Files

Arranging your model files well will make Dart JSON deserialization easier and more expected.

Suggested File Structure:

/models/
  user.dart
  user.g.dart
  address.dart
  address.g.dart

Each model should be in its own file. This stops confusion with generated files and makes sure updates are simple.

Use a Barrel File

Make a models.dart or models/index.dart and export all models from it:

export 'user.dart';
export 'address.dart';

Barrel files make imports simpler throughout your app. They also cut down on wrongly placed serialization code.


Regenerate with Confidence

Serialization code does not "just work." Here is how to make it again safely:

  1. Save all files you edited.
  2. Delete old .g.dart if it is outdated or broken:
    flutter pub run build_runner clean
    
  3. Rebuild your serialization code cleanly:
    flutter pub run build_runner build --delete-conflicting-outputs
    

    This makes sure that overwritten files will not fail without a clear message if the generator has conflicts.


More Ways to Use Custom Deserialization Logic

Sometimes, you need more control than the default json_serializable offers. That is when @JsonKey is useful.

Example: Reading Dates or Enums

@JsonSerializable()
class Booking {
  @JsonKey(fromJson: _parseDate, toJson: _formatDate)
  final DateTime date;

  Booking({required this.date});

  factory Booking.fromJson(Map<String, dynamic> json) => _$BookingFromJson(json);
  Map<String, dynamic> toJson() => _$BookingToJson(this);

  static DateTime _parseDate(String date) => DateTime.parse(date);
  static String _formatDate(DateTime date) => date.toIso8601String();
}

Use this for:

  • 🗓 Date/time changes
  • 🎨 Enum changes
  • 🔐 Specific mappings
  • 🧩 Deeply nested lists or objects

How to Prevent JSON Deserialization Issues Later

Here is how to get ahead of future fromJson problems:

  • ✅ Run unit tests that read real JSON responses.
  • ✅ Check models against backend contracts or OpenAPI specs.
  • ✅ Add code generation steps to your CI pipeline.
  • ✅ Keep model names and paths the same and clear.
  • ✅ Use tools like json_serializable and freezed together for data that cannot change and can be serialized.

Good team consistency and automation are your best ways to protect your code.


Suggested Tools & Libraries

These libraries can greatly improve how your Dart JSON deserialization works:

  • json_serializable: Dart’s official way for serialization using code generation.
  • freezed: Data classes with json_serializable support built-in.
  • equatable: Makes value comparisons for models simpler.
  • ✅ VSCode Extensions (like "Flutter JSON to Dart"): Good for quick setup code.
  • build_runner: This is the main part of Dart's code generation system.

When used correctly, these tools make handling models in Flutter strong and trustworthy for apps meant for production.


Main Checklist: Finding fromJson Problems

✅ Check Description
@JsonSerializable() is there On every model, nested or not
part 'model.g.dart' is there Matches filename exactly
factory Model.fromJson() is there Needed for code use
flutter pub run build_runner build ran Do not skip this step
Scripts re-import generated files Has correct imports
Model fields match JSON keys Or mapping does not work
No typos in factory constructors Dart does not give an error if things are quiet

Use this checklist before you take apart your code. Most fromJson problems (95%) can be fixed with these checks.


Build Better with Nested Serialization

Dart JSON deserialization works very well. But only if set up right. If you see a json_serializable fromJson error, it is likely from mistakes you could have stopped in your model file or build process. The main point: Dart will not deserialize nested classes unless they have annotations, are linked with part, and had code made for them using build_runner.

Think of JSON serialization as real project basics. Keep your models simple, test them early, and make your generations automatic. When you do these things, fromJson errors will stop happening. And your Flutter apps will be much stronger, simpler, and ready for use.


Citations

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading