The Schrodinger Fastjson Bug: Why Random Cast Errors Occur
A developer chronicles a perplexing Fastjson bug where identical JSON data intermittently triggers a 'can not cast to String' error, explains how generic type caching caused the issue, and shows how upgrading from version 1.2.29 to 1.2.33 resolves it.
Preface
After years of development, I have encountered countless bugs, but this particular one was especially elusive. It appeared simple at first, yet its occurrence was sporadic and hard to reproduce, prompting a detailed investigation.
Cause
A colleague submitted a feature for testing, and during testing a backend error surfaced:
com.alibaba.fastjson.JSONException: can not cast to String, value : {"code":"00","msg":"成功","data":{...}}
at com.alibaba.fastjson.util.TypeUtils.castToInt(TypeUtils.java:564)
at com.alibaba.fastjson.serializer.IntegerCodec.deserialze(IntegerCodec.java:89)The error seemed straightforward—a type mismatch in Fastjson conversion—but the team could not locate the problem in the code.
When debugging remotely, the issue disappeared, only to reappear after removing breakpoints, suggesting the bug depended on observation.
The relevant code (simplified) looks like this:
public <T> T executeLua(String luaName, Class<T> c, Object... args) {
String json = executor.execute(luaName, args);
log.info("Execution result: {}", json);
T result = JSON.parseObject(json, c);
return result;
}Invocation example:
LuaResult result = executeLua("xxxx", LuaResult.class, args);The generic type T corresponds to a simple LuaResult class:
public class LuaResult<T> {
protected String code;
protected String msg;
protected T data;
...
}Local tests with the same JSON data parsed correctly, even under multithreaded loops, yet the server environment produced intermittent errors.
Investigation (1)
The JSON data is correct, so the problem points to Fastjson itself, which in the project is version 1.2.29. The bug manifested only under certain execution orders and disappeared when debugging.
Switching to another JSON library or upgrading Fastjson would hide the issue, but I wanted to understand the root cause.
Investigation (2)
Adding explicit generic types using TypeReference eliminated the error, leading to the discovery that Fastjson caches the generic type of the previous parsing of the same object. This cache caused the “cannot cast to int” error when a non‑generic call followed a generic one.
To reproduce the bug, I wrote the following code (using Fastjson 1.2.29):
public static void main(String... args) throws Exception {
try {
String json = "{\"code\":\"00\",\"msg\":\"成功\",\"data\":{\"xxx\":21,\"yyy\":5}}";
LuaResult result = JSON.parseObject(json, LuaResult.class);
System.out.println(result);
} catch (Exception e) {
log.error("Error", e);
}
try {
String json1 = "{\"msg\":\"成功\",\"data\":\"31\",\"code\":\"00\"}";
LuaResult<Integer> result = JSON.parseObject(json1, new TypeReference<LuaResult<Integer>>() {});
System.out.println(result);
} catch (Exception e) {
log.error("Error", e);
}
// The third block triggers the bug when executed after the above two
try {
String json = "{\"code\":\"00\",\"msg\":\"成功\",\"data\":{\"xxx\":21,\"yyy\":5}}";
LuaResult result = JSON.parseObject(json, LuaResult.class);
System.out.println(result);
} catch (Exception e) {
log.error("Error", e);
}
}Running this sequence produces the same intermittent exception observed in production. Changing the order of the three blocks eliminates the error, confirming the cache behavior.
Upgrading Fastjson step‑by‑step revealed that the bug disappears starting from version 1.2.33, where the author fixed the issue related to generic parsing without explicit type parameters.
Conclusion
The “Schrodinger” bug was caused by Fastjson’s early‑version handling of generic types, which cached the previous generic definition and applied it to subsequent parses lacking explicit generics, leading to cast failures.
Resolving the issue is straightforward: upgrade Fastjson to version 1.2.33 or later.
Understanding the underlying cause, rather than merely upgrading, provides deeper insight into library behavior and helps avoid similar pitfalls in future projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Xiao Lou's Tech Notes
Backend technology sharing, architecture design, performance optimization, source code reading, troubleshooting, and pitfall practices
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
