title: Troubleshooting sidebar_position: 90 id: troubleshooting license: | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
This page covers common issues and their solutions.
If you explicitly disabled compatible mode and get a strange serialization error, it may be caused by class inconsistency between the serialization peer and deserialization peer.
In such cases, you can invoke ForyBuilder#withClassVersionCheck with withCompatible(false) to validate it. If deserialization throws org.apache.fory.exception.ClassNotCompatibleException, the classes are inconsistent. Remove the withCompatible(false) override unless every reader and writer always uses the same class schema.
// Enable class version check to diagnose issues Fory fory = Fory.builder() .withCompatible(false) .withClassVersionCheck(true) .build(); // If ClassNotCompatibleException is thrown, remove withCompatible(false).
Note: compatible mode is the default for both xlang and native mode. Use withCompatible(false) only if every reader and writer always uses the same class schema and you want faster serialization and smaller size.
Use serialize with one of the deserialize overloads:
| Serialization API | Deserialization API |
|---|---|
Fory#serialize | Fory#deserialize |
Wrong usage example:
// Wrong: deserialize with an incompatible target class byte[] bytes = fory.serialize(struct1); Struct2 result = fory.deserialize(bytes, Struct2.class); // May throw ClassCastException
Correct usage:
byte[] bytes = fory.serialize(object); Object result = fory.deserialize(bytes); byte[] typedBytes = fory.serialize(object); MyClass typedResult = fory.deserialize(typedBytes, MyClass.class);
If you want to serialize one POJO and deserialize it into a different POJO type, use compatible mode:
public class DeserializeIntoType { static class Struct1 { int f1; String f2; public Struct1(int f1, String f2) { this.f1 = f1; this.f2 = f2; } } static class Struct2 { int f1; String f2; double f3; } static ThreadSafeFory fory = Fory.builder() .buildThreadSafeFory(); public static void main(String[] args) { Struct1 struct1 = new Struct1(10, "abc"); byte[] data = fory.serialize(struct1); Struct2 struct2 = fory.deserialize(data, Struct2.class); } }
Fory supports cyclic references in object fields, arrays, lists, and map values. However, an object that participates in a cycle must not be used as a Set element or a Map key. This restriction applies to both hash-based and sorted containers, such as HashSet, TreeSet, HashMap, and TreeMap.
While resolving a cycle, Fory may expose an object‘s identity before all of its fields have been deserialized. A container can therefore call hashCode(), equals(), compareTo(), or a comparator while the object is only partially initialized. If later fields affect those methods, the container’s hash buckets or ordering become invalid. The object may still appear during iteration even though contains() or get() cannot find it.
When a set view is required, serialize the cyclic references as a list and derive a transient set after deserialization:
import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; public final class Node { private final List<Node> parentList = new ArrayList<>(); private transient Set<Node> parents; public Set<Node> getParents() { if (parents == null) { parents = new LinkedHashSet<>(parentList); } return parents; } }
For a derived map, serialize an ordered list of key-value entries and build the transient map after deserialization.
Cause: Class registration is required but the class wasn't registered.
Solution: Register the class before serialization:
fory.register(MyClass.class); // or with explicit ID fory.register(MyClass.class, 100);
Cause: Class schema differs between serialization and deserialization.
Solution: Keep compatible mode enabled:
Fory fory = Fory.builder() .build();
Cause: Object graph is too deep, possibly indicating a circular reference attack.
Solution: Increase max depth if legitimate, or check for malicious data:
Fory fory = Fory.builder() .withMaxDepth(100) // Increase from default 50 .build();
Cause: No serializer registered for the type.
Solution: Register a custom serializer:
fory.registerSerializer(MyClass.class, new MyClassSerializer(fory.getTypeResolver()));
On JDK25+, opening java.lang.invoke to Fory core is also recommended. Add the opening if an error names java.base/java.lang.invoke, or when Unsafe access is disabled or unavailable, including with --sun-misc-unsafe-memory-access=deny. Use ALL-UNNAMED when Fory is on the classpath:
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
Use the Fory core module name when Fory is on the module path:
--add-opens=java.base/java.lang.invoke=org.apache.fory.core
Fory does not require application package opens for private-field access.
Cause: JIT compilation happening on first serialization.
Solution: Enable async compilation:
Fory fory = Fory.builder() .withAsyncCompilation(true) .build();
Cause: Large object graphs or reference tracking overhead.
Solutions:
.withRefTracking(false)Cause: Metadata overhead or uncompressed data.
Solutions:
.withIntCompressed(true), .withLongCompressed(true)FORY_LOG_LEVEL=INFO mvn test -Dtest=org.apache.fory.TestClass#testMethod