ZetCode

Java InvalidClassException Class

Last modified: April 16, 2025

The java.io.InvalidClassException is thrown during serialization or deserialization when the serialization runtime detects problems with a class. These problems include incompatible class versions or missing serialVersionUID.

This exception typically occurs when the serialized class definition has changed between serialization and deserialization. The JVM uses serialVersionUID to verify compatibility. Without explicit declaration, it's automatically generated.

InvalidClassException Class Overview

InvalidClassException extends ObjectStreamException and indicates serialization problems. It provides detailed information about the failure through its message. The classname and explanation are typically included.

public class InvalidClassException extends ObjectStreamException {
    public String classname;
    public InvalidClassException(String reason);
    public InvalidClassException(String cname, String reason);
    public String getMessage();
}

The code above shows the structure of InvalidClassException. The classname field holds the problematic class name. Constructors allow specifying the reason and classname. The getMessage method combines both in the message.

Basic Serialization Example

This example demonstrates basic serialization where no exception occurs. We'll serialize and deserialize a simple Person object. The class implements Serializable and declares serialVersionUID.

Main.java
import java.io.*;

class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("John Doe", 30);
        
        // Serialize
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("person.ser"))) {
            oos.writeObject(person);
            System.out.println("Serialization complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Deserialize
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("person.ser"))) {
            Person deserialized = (Person) ois.readObject();
            System.out.println("Deserialized: " + deserialized.name);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

This example shows successful serialization and deserialization. The Person class has serialVersionUID declared. Without changes to the class, deserialization works fine. The next examples will show scenarios causing InvalidClassException.

Missing serialVersionUID

When serialVersionUID is missing, the JVM generates one based on class structure. Changing the class structure makes the generated UID incompatible. This causes InvalidClassException during deserialization.

Main.java
import java.io.*;

// Version 1: Original class without serialVersionUID
class Product implements Serializable {
    String name;
    double price;
    
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
}

public class Main {
    public static void main(String[] args) {
        // Serialize original version
        Product product = new Product("Laptop", 999.99);
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("product.ser"))) {
            oos.writeObject(product);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Simulate class change by adding a new field
        class Product implements Serializable {
            String name;
            double price;
            int quantity;  // Added field
            
            public Product(String name, double price) {
                this.name = name;
                this.price = price;
            }
        }
        
        // Attempt deserialization
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("product.ser"))) {
            Product deserialized = (Product) ois.readObject();
            System.out.println("Deserialized: " + deserialized.name);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();  // Will throw InvalidClassException
        }
    }
}

This example demonstrates InvalidClassException due to missing serialVersionUID. After serializing the original Product, we modified the class by adding a field. Deserialization fails because the generated UIDs don't match. Always declare serialVersionUID for serializable classes.

Incompatible serialVersionUID

Explicit serialVersionUID values must match between serialization and deserialization. Changing this value manually causes InvalidClassException. This example shows the scenario with mismatched UIDs.

Main.java
import java.io.*;

class Employee implements Serializable {
    private static final long serialVersionUID = 1L;  // Original UID
    String name;
    String department;
    
    public Employee(String name, String department) {
        this.name = name;
        this.department = department;
    }
}

public class Main {
    public static void main(String[] args) {
        // Serialize with original UID
        Employee emp = new Employee("Alice", "Engineering");
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("employee.ser"))) {
            oos.writeObject(emp);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Simulate UID change
        class Employee implements Serializable {
            private static final long serialVersionUID = 2L;  // Changed UID
            String name;
            String department;
            
            public Employee(String name, String department) {
                this.name = name;
                this.department = department;
            }
        }
        
        // Attempt deserialization
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("employee.ser"))) {
            Employee deserialized = (Employee) ois.readObject();
            System.out.println("Deserialized: " + deserialized.name);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();  // InvalidClassException: incompatible UIDs
        }
    }
}

This example shows InvalidClassException caused by changing serialVersionUID. The serialized data has UID=1, but the class now expects UID=2. The exception message will indicate the mismatched UIDs. Never change serialVersionUID unless you're intentionally making incompatible changes.

Class Structure Changes

Certain class structure changes are incompatible even with matching serialVersionUID. Changing field types or removing fields causes InvalidClassException. This example demonstrates such incompatible changes.

Main.java
import java.io.*;

class Account implements Serializable {
    private static final long serialVersionUID = 1L;
    String accountNumber;
    double balance;  // Original type: double
    
    public Account(String accountNumber, double balance) {
        this.accountNumber = accountNumber;
        this.balance = balance;
    }
}

public class Main {
    public static void main(String[] args) {
        // Serialize original version
        Account acc = new Account("123456", 1000.0);
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileInputStream("account.ser"))) {
            oos.writeObject(acc);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Simulate incompatible change: change balance type to String
        class Account implements Serializable {
            private static final long serialVersionUID = 1L;  // Same UID
            String accountNumber;
            String balance;  // Changed type
            
            public Account(String accountNumber, String balance) {
                this.accountNumber = accountNumber;
                this.balance = balance;
            }
        }
        
        // Attempt deserialization
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("account.ser"))) {
            Account deserialized = (Account) ois.readObject();
            System.out.println("Deserialized: " + deserialized.accountNumber);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();  // InvalidClassException: incompatible types
        }
    }
}

This example shows InvalidClassException due to incompatible field type change. Even with matching serialVersionUID, changing balance from double to String breaks deserialization. The serialization system cannot automatically convert between these types. Such changes require custom readObject/writeObject methods.

Missing Class Definition

InvalidClassException occurs when the class definition is unavailable during deserialization. This happens when the class was available during serialization but is missing during deserialization. The example simulates this scenario.

Main.java
import java.io.*;

// Original class that will be serialized
class Customer implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    String email;
    
    public Customer(String name, String email) {
        this.name = name;
        this.email = email;
    }
}

public class Main {
    public static void main(String[] args) {
        // Serialize Customer object
        Customer cust = new Customer("Bob", "bob@example.com");
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("customer.ser"))) {
            oos.writeObject(cust);
            System.out.println("Serialization complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Simulate missing class by not having Customer class definition
        // during deserialization
        
        // Attempt deserialization without Customer class
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("customer.ser"))) {
            Object deserialized = ois.readObject();
            System.out.println("Deserialized: " + deserialized.getClass());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();  // InvalidClassException: class not found
        }
    }
}

This example demonstrates InvalidClassException due to missing class definition. The Customer class was available during serialization but not during deserialization. The exception message will indicate the missing class name. Ensure class definitions are available in the classpath during deserialization.

Custom serialPersistentFields

Using serialPersistentFields to control serialization can lead to InvalidClassException if not handled carefully. This example shows incorrect usage where the declared fields don't match the actual class fields.

Main.java
import java.io.*;
import java.io.ObjectStreamField;

class Settings implements Serializable {
    private static final long serialVersionUID = 1L;
    
    // Incorrect serialPersistentFields - missing 'darkMode' field
    private static final ObjectStreamField[] serialPersistentFields = {
        new ObjectStreamField("language", String.class)
    };
    
    String language;
    boolean darkMode;
    
    public Settings(String language, boolean darkMode) {
        this.language = language;
        this.darkMode = darkMode;
    }
}

public class Main {
    public static void main(String[] args) {
        // Serialize
        Settings settings = new Settings("en", true);
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("settings.ser"))) {
            oos.writeObject(settings);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // Attempt deserialization
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("settings.ser"))) {
            Settings deserialized = (Settings) ois.readObject();
            System.out.println("Language: " + deserialized.language);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();  // InvalidClassException: field mismatch
        }
    }
}

This example shows InvalidClassException caused by incorrect serialPersistentFields. The array declares only 'language' field while the class has 'darkMode' too. The serialization system detects this mismatch. When using serialPersistentFields, ensure all serializable fields are properly declared.

Source

Java InvalidClassException Class Documentation

In this article, we've covered common scenarios that cause InvalidClassException during Java serialization. Understanding these cases helps prevent and troubleshoot serialization issues in Java applications.

Author

My name is Jan Bodnar, and I am a dedicated programmer with many years of experience in the field. I began writing programming articles in 2007 and have since authored over 1,400 articles and eight e-books. With more than eight years of teaching experience, I am committed to sharing my knowledge and helping others master programming concepts.

List all Java tutorials.