Complete Java InvalidClassException class tutorial covering all scenarios with examples. Learn about serialization issues in Java.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.