skylot/jadx · error · JadxRuntimeException
Cannot save type:
Error message
Cannot save type:
What it means
Thrown by ClsSet.writeArgType during serialization when an ArgType does not match any of the recognized type categories (primitive, outer-generic, wildcard, generic, generic-type-variable, object, or array). The method cascades through if-else checks for each type kind and throws if none match. This indicates the ArgType is in an unexpected or corrupt state that the serializer cannot handle.
Source
Thrown at jadx-core/src/main/java/jadx/core/clsp/ClsSet.java:303
if (bound != ArgType.WildcardBound.UNBOUND) {
writeArgType(out, argType.getWildcardType(), names);
}
} else if (argType.isGeneric()) {
out.writeByte(TypeEnum.GENERIC.ordinal());
out.writeInt(getCls(argType, names).getId());
writeArgTypesList(out, argType.getGenericTypes(), names);
} else if (argType.isGenericType()) {
out.writeByte(TypeEnum.GENERIC_TYPE_VARIABLE.ordinal());
writeString(out, argType.getObject());
writeArgTypesList(out, argType.getExtendTypes(), names);
} else if (argType.isObject()) {
out.writeByte(TypeEnum.OBJECT.ordinal());
out.writeInt(getCls(argType, names).getId());
} else if (argType.isArray()) {
out.writeByte(TypeEnum.ARRAY.ordinal());
writeArgType(out, argType.getArrayElement(), names);
} else {
throw new JadxRuntimeException("Cannot save type: " + argType);
}
}
private void load(InputStream input) throws IOException, DecodeException {
try (DataInputStream in = new DataInputStream(new BufferedInputStream(input))) {
byte[] header = new byte[JADX_CLS_SET_HEADER.length()];
int readHeaderLength = in.read(header);
if (readHeaderLength != JADX_CLS_SET_HEADER.length()
|| !JADX_CLS_SET_HEADER.equals(new String(header, STRING_CHARSET))) {
throw new DecodeException("Wrong jadx class set header");
}
int version = in.readByte();
if (version != VERSION) {
throw new DecodeException("Wrong jadx class set version, got: " + version + ", expect: " + VERSION);
}
androidApiLevel = in.readInt();
int clsCount = in.readInt();
classes = new ClspClass[clsCount];View on GitHub (pinned to e738a26571)
Solutions
- Inspect the ArgType value in the error message to determine its state (call isPrimitive, isObject, etc. to see which predicates fail).
- Report as a jadx internal bug — all valid ArgType states should be serializable; a gap means writeArgType needs a new branch.
- If writing a custom jadx extension that produces ArgType instances, ensure they satisfy at least one category predicate (isPrimitive, isObject, isArray, isGeneric, isGenericType, getOuterType, or getWildcardType).
Defensive patterns
Strategy: try-catch
Type guard
// Check that an ArgType falls into at least one serializable category
static boolean isSerializableArgType(ArgType t) {
return t == null
|| t.isPrimitive()
|| t.getOuterType() != null
|| t.getWildcardType() != null
|| t.isGeneric()
|| t.isGenericType()
|| t.isObject()
|| t.isArray();
} Try / catch
try {
clsSet.save(outputPath);
} catch (JadxRuntimeException e) {
if (e.getMessage().startsWith("Cannot save type:")) {
LOG.error("Unserializable ArgType encountered: {}", e.getMessage());
// report which type caused the failure
} else {
throw e;
}
} Prevention
- Report this as a jadx internal bug if encountered — all valid ArgType states should be serializable.
- Check the ArgType value in the message to understand which predicate it fails.
- Avoid custom ArgType subclasses or modifications that create unhandled type states.
When it happens
Trigger: Calling ClsSet.save (which calls writeArgType for every type in the class set) where an ArgType instance has an internal state that does not satisfy any of the isPrimitive/getOuterType/getWildcardType/isGeneric/isGenericType/isObject/isArray predicates. This could happen if a custom ArgType subclass or a malformed ArgType is present in the class graph.
Common situations: A jadx internal bug where a new ArgType variant is introduced without updating writeArgType. Processing obfuscated bytecode that produces an ArgType in an inconsistent state. Custom jadx extensions that create ArgType instances without populating the expected fields. Extremely rare in normal operation.
Related errors
- Missing class:
- Wrong jadx class set header
- Wrong jadx class set version, got:
- Can't load classpath file:
- Duplicate class:
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/b2a1593f68be72da.
Report an issue: GitHub.